Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
diff --git a/Documentation/block/ioprio.txt b/Documentation/block/ioprio.txt
new file mode 100644
index 0000000..96ccf68
--- /dev/null
+++ b/Documentation/block/ioprio.txt
@@ -0,0 +1,176 @@
+Block io priorities
+===================
+
+
+Intro
+-----
+
+With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
+priorities is supported for reads on files. This enables users to io nice
+processes or process groups, similar to what has been possible to cpu
+scheduling for ages. This document mainly details the current possibilites
+with cfq, other io schedulers do not support io priorities so far.
+
+Scheduling classes
+------------------
+
+CFQ implements three generic scheduling classes that determine how io is
+served for a process.
+
+IOPRIO_CLASS_RT: This is the realtime io class. This scheduling class is given
+higher priority than any other in the system, processes from this class are
+given first access to the disk every time. Thus it needs to be used with some
+care, one io RT process can starve the entire system. Within the RT class,
+there are 8 levels of class data that determine exactly how much time this
+process needs the disk for on each service. In the future this might change
+to be more directly mappable to performance, by passing in a wanted data
+rate instead.
+
+IOPRIO_CLASS_BE: This is the best-effort scheduling class, which is the default
+for any process that hasn't set a specific io priority. The class data
+determines how much io bandwidth the process will get, it's directly mappable
+to the cpu nice levels just more coarsely implemented. 0 is the highest
+BE prio level, 7 is the lowest. The mapping between cpu nice level and io
+nice level is determined as: io_nice = (cpu_nice + 20) / 5.
+
+IOPRIO_CLASS_IDLE: This is the idle scheduling class, processes running at this
+level only get io time when no one else needs the disk. The idle class has no
+class data, since it doesn't really apply here.
+
+Tools
+-----
+
+See below for a sample ionice tool. Usage:
+
+# ionice -c<class> -n<level> -p<pid>
+
+If pid isn't given, the current process is assumed. IO priority settings
+are inherited on fork, so you can use ionice to start the process at a given
+level:
+
+# ionice -c2 -n0 /bin/ls
+
+will run ls at the best-effort scheduling class at the highest priority.
+For a running process, you can give the pid instead:
+
+# ionice -c1 -n2 -p100
+
+will change pid 100 to run at the realtime scheduling class, at priority 2.
+
+---> snip ionice.c tool <---
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <asm/unistd.h>
+
+extern int sys_ioprio_set(int, int, int);
+extern int sys_ioprio_get(int, int);
+
+#if defined(__i386__)
+#define __NR_ioprio_set		289
+#define __NR_ioprio_get		290
+#elif defined(__ppc__)
+#define __NR_ioprio_set		273
+#define __NR_ioprio_get		274
+#elif defined(__x86_64__)
+#define __NR_ioprio_set		251
+#define __NR_ioprio_get		252
+#elif defined(__ia64__)
+#define __NR_ioprio_set		1274
+#define __NR_ioprio_get		1275
+#else
+#error "Unsupported arch"
+#endif
+
+_syscall3(int, ioprio_set, int, which, int, who, int, ioprio);
+_syscall2(int, ioprio_get, int, which, int, who);
+
+enum {
+	IOPRIO_CLASS_NONE,
+	IOPRIO_CLASS_RT,
+	IOPRIO_CLASS_BE,
+	IOPRIO_CLASS_IDLE,
+};
+
+enum {
+	IOPRIO_WHO_PROCESS = 1,
+	IOPRIO_WHO_PGRP,
+	IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT	13
+
+const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
+
+int main(int argc, char *argv[])
+{
+	int ioprio = 4, set = 0, ioprio_class = IOPRIO_CLASS_BE;
+	int c, pid = 0;
+
+	while ((c = getopt(argc, argv, "+n:c:p:")) != EOF) {
+		switch (c) {
+		case 'n':
+			ioprio = strtol(optarg, NULL, 10);
+			set = 1;
+			break;
+		case 'c':
+			ioprio_class = strtol(optarg, NULL, 10);
+			set = 1;
+			break;
+		case 'p':
+			pid = strtol(optarg, NULL, 10);
+			break;
+		}
+	}
+
+	switch (ioprio_class) {
+		case IOPRIO_CLASS_NONE:
+			ioprio_class = IOPRIO_CLASS_BE;
+			break;
+		case IOPRIO_CLASS_RT:
+		case IOPRIO_CLASS_BE:
+			break;
+		case IOPRIO_CLASS_IDLE:
+			ioprio = 7;
+			break;
+		default:
+			printf("bad prio class %d\n", ioprio_class);
+			return 1;
+	}
+
+	if (!set) {
+		if (!pid && argv[optind])
+			pid = strtol(argv[optind], NULL, 10);
+
+		ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
+
+		printf("pid=%d, %d\n", pid, ioprio);
+
+		if (ioprio == -1)
+			perror("ioprio_get");
+		else {
+			ioprio_class = ioprio >> IOPRIO_CLASS_SHIFT;
+			ioprio = ioprio & 0xff;
+			printf("%s: prio %d\n", to_prio[ioprio_class], ioprio);
+		}
+	} else {
+		if (ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio | ioprio_class << IOPRIO_CLASS_SHIFT) == -1) {
+			perror("ioprio_set");
+			return 1;
+		}
+
+		if (argv[optind])
+			execvp(argv[optind], &argv[optind]);
+	}
+
+	return 0;
+}
+
+---> snip ionice.c tool <---
+
+
+March 11 2005, Jens Axboe <axboe@suse.de>
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
index d599beb..c8f9a73 100644
--- a/Documentation/cciss.txt
+++ b/Documentation/cciss.txt
@@ -17,6 +17,7 @@
 	* SA P600
 	* SA P800
 	* SA E400
+	* SA E300
 
 If nodes are not already created in the /dev/cciss directory, run as root:
 
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index f44bb55..89cd417 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1115,7 +1115,7 @@
 			See Documentation/ramdisk.txt.
 
 	psmouse.proto=  [HW,MOUSE] Highest PS2 mouse protocol extension to
-			probe for (bare|imps|exps).
+			probe for (bare|imps|exps|lifebook|any).
 	psmouse.rate=	[HW,MOUSE] Set desired mouse report rate, in reports
 			per second.
 	psmouse.resetafter=
diff --git a/MAINTAINERS b/MAINTAINERS
index a0b0d59..4db63de 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1149,7 +1149,7 @@
 
 INFINIBAND SUBSYSTEM
 P:	Roland Dreier
-M:	roland@topspin.com
+M:	rolandd@cisco.com
 P:	Sean Hefty
 M:	mshefty@ichips.intel.com
 P:	Hal Rosenstock
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 8f146a4..bbea636 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -32,6 +32,7 @@
 #include <asm/leds.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
+#include <asm/mach/time.h>
 
 extern const char *processor_modes[];
 extern void setup_mm_for_reboot(char mode);
@@ -85,8 +86,10 @@
 void default_idle(void)
 {
 	local_irq_disable();
-	if (!need_resched() && !hlt_counter)
+	if (!need_resched() && !hlt_counter) {
+		timer_dyn_reprogram();
 		arch_idle();
+	}
 	local_irq_enable();
 }
 
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 06054c9..1b7fcd5 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -424,15 +424,19 @@
 	return ret;
 }
 
+/*
+ * Reprogram the system timer for at least the calculated time interval.
+ * This function should be called from the idle thread with IRQs disabled,
+ * immediately before sleeping.
+ */
 void timer_dyn_reprogram(void)
 {
 	struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
-	unsigned long flags;
 
-	write_seqlock_irqsave(&xtime_lock, flags);
+	write_seqlock(&xtime_lock);
 	if (dyn_tick->state & DYN_TICK_ENABLED)
 		dyn_tick->reprogram(next_timer_interrupt() - jiffies);
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	write_sequnlock(&xtime_lock);
 }
 
 static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
diff --git a/arch/arm/mach-aaec2000/Makefile.boot b/arch/arm/mach-aaec2000/Makefile.boot
new file mode 100644
index 0000000..8f5a8b7
--- /dev/null
+++ b/arch/arm/mach-aaec2000/Makefile.boot
@@ -0,0 +1 @@
+	zreladdr-y := 0xf0008000
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index c08710b..6dcb23d 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -522,6 +522,69 @@
 		printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
 }
 
+static inline void
+free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
+{
+	struct page *start_pg, *end_pg;
+	unsigned long pg, pgend;
+
+	/*
+	 * Convert start_pfn/end_pfn to a struct page pointer.
+	 */
+	start_pg = pfn_to_page(start_pfn);
+	end_pg = pfn_to_page(end_pfn);
+
+	/*
+	 * Convert to physical addresses, and
+	 * round start upwards and end downwards.
+	 */
+	pg = PAGE_ALIGN(__pa(start_pg));
+	pgend = __pa(end_pg) & PAGE_MASK;
+
+	/*
+	 * If there are free pages between these,
+	 * free the section of the memmap array.
+	 */
+	if (pg < pgend)
+		free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
+}
+
+/*
+ * The mem_map array can get very big.  Free the unused area of the memory map.
+ */
+static void __init free_unused_memmap_node(int node, struct meminfo *mi)
+{
+	unsigned long bank_start, prev_bank_end = 0;
+	unsigned int i;
+
+	/*
+	 * [FIXME] This relies on each bank being in address order.  This
+	 * may not be the case, especially if the user has provided the
+	 * information on the command line.
+	 */
+	for (i = 0; i < mi->nr_banks; i++) {
+		if (mi->bank[i].size == 0 || mi->bank[i].node != node)
+			continue;
+
+		bank_start = mi->bank[i].start >> PAGE_SHIFT;
+		if (bank_start < prev_bank_end) {
+			printk(KERN_ERR "MEM: unordered memory banks.  "
+				"Not freeing memmap.\n");
+			break;
+		}
+
+		/*
+		 * If we had a previous bank, and there is a space
+		 * between the current bank and the previous, free it.
+		 */
+		if (prev_bank_end && prev_bank_end != bank_start)
+			free_memmap(node, prev_bank_end, bank_start);
+
+		prev_bank_end = (mi->bank[i].start +
+				 mi->bank[i].size) >> PAGE_SHIFT;
+	}
+}
+
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much
  * memory is free.  This is done after various parts of the system have
@@ -540,16 +603,12 @@
 	max_mapnr   = virt_to_page(high_memory) - mem_map;
 #endif
 
-	/*
-	 * We may have non-contiguous memory.
-	 */
-	if (meminfo.nr_banks != 1)
-		create_memmap_holes(&meminfo);
-
 	/* this will put all unused low memory onto the freelists */
 	for_each_online_node(node) {
 		pg_data_t *pgdat = NODE_DATA(node);
 
+		free_unused_memmap_node(node, &meminfo);
+
 		if (pgdat->node_spanned_pages != 0)
 			totalram_pages += free_all_bootmem_node(pgdat);
 	}
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 2c2b93d..052ab44 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -169,7 +169,14 @@
 
 	memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
 
+	/*
+	 * Copy over the kernel and IO PGD entries
+	 */
 	init_pgd = pgd_offset_k(0);
+	memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+		       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
+
+	clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
 
 	if (!vectors_high()) {
 		/*
@@ -198,14 +205,6 @@
 		spin_unlock(&mm->page_table_lock);
 	}
 
-	/*
-	 * Copy over the kernel and IO PGD entries
-	 */
-	memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
-		       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
-
-	clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
-
 	return new_pgd;
 
 no_pte:
@@ -698,75 +697,3 @@
 	for (i = 0; i < nr; i++)
 		create_mapping(io_desc + i);
 }
-
-static inline void
-free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
-{
-	struct page *start_pg, *end_pg;
-	unsigned long pg, pgend;
-
-	/*
-	 * Convert start_pfn/end_pfn to a struct page pointer.
-	 */
-	start_pg = pfn_to_page(start_pfn);
-	end_pg = pfn_to_page(end_pfn);
-
-	/*
-	 * Convert to physical addresses, and
-	 * round start upwards and end downwards.
-	 */
-	pg = PAGE_ALIGN(__pa(start_pg));
-	pgend = __pa(end_pg) & PAGE_MASK;
-
-	/*
-	 * If there are free pages between these,
-	 * free the section of the memmap array.
-	 */
-	if (pg < pgend)
-		free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
-}
-
-static inline void free_unused_memmap_node(int node, struct meminfo *mi)
-{
-	unsigned long bank_start, prev_bank_end = 0;
-	unsigned int i;
-
-	/*
-	 * [FIXME] This relies on each bank being in address order.  This
-	 * may not be the case, especially if the user has provided the
-	 * information on the command line.
-	 */
-	for (i = 0; i < mi->nr_banks; i++) {
-		if (mi->bank[i].size == 0 || mi->bank[i].node != node)
-			continue;
-
-		bank_start = mi->bank[i].start >> PAGE_SHIFT;
-		if (bank_start < prev_bank_end) {
-			printk(KERN_ERR "MEM: unordered memory banks.  "
-				"Not freeing memmap.\n");
-			break;
-		}
-
-		/*
-		 * If we had a previous bank, and there is a space
-		 * between the current bank and the previous, free it.
-		 */
-		if (prev_bank_end && prev_bank_end != bank_start)
-			free_memmap(node, prev_bank_end, bank_start);
-
-		prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
-					   mi->bank[i].size) >> PAGE_SHIFT;
-	}
-}
-
-/*
- * The mem_map array can get very big.  Free
- * the unused area of the memory map.
- */
-void __init create_memmap_holes(struct meminfo *mi)
-{
-	int node;
-
-	for_each_online_node(node)
-		free_unused_memmap_node(node, mi);
-}
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 30c1dfb..6d3a79e 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Thu Mar 24 14:34:50 2005
+# Last update: Thu Jun 23 20:19:33 2005
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -243,7 +243,7 @@
 jasper			ARCH_JASPER		JASPER			232
 dsc25			ARCH_DSC25		DSC25			233
 omap_innovator		MACH_OMAP_INNOVATOR	OMAP_INNOVATOR		234
-ramses			ARCH_RAMSES		RAMSES			235
+mnci			ARCH_RAMSES		RAMSES			235
 s28x			ARCH_S28X		S28X			236
 mport3			ARCH_MPORT3		MPORT3			237
 pxa_eagle250		ARCH_PXA_EAGLE250	PXA_EAGLE250		238
@@ -323,7 +323,7 @@
 nimbra210		ARCH_NIMBRA210		NIMBRA210		312
 hhp_d95xx		ARCH_HHP_D95XX		HHP_D95XX		313
 labarm			ARCH_LABARM		LABARM			314
-m825xx			ARCH_M825XX		M825XX			315
+comcerto		ARCH_M825XX		M825XX			315
 m7100			SA1100_M7100		M7100			316
 nipc2			ARCH_NIPC2		NIPC2			317
 fu7202			ARCH_FU7202		FU7202			318
@@ -724,3 +724,66 @@
 omap_comet3		MACH_COMET3		COMET3			716
 omap_comet4		MACH_COMET4		COMET4			717
 csb625			MACH_CSB625		CSB625			718
+fortunet2		MACH_FORTUNET2		FORTUNET2		719
+s5h2200			MACH_S5H2200		S5H2200			720
+optorm920		MACH_OPTORM920		OPTORM920		721
+adsbitsyxb		MACH_ADSBITSYXB		ADSBITSYXB		722
+adssphere		MACH_ADSSPHERE		ADSSPHERE		723
+adsportal		MACH_ADSPORTAL		ADSPORTAL		724
+ln2410sbc		MACH_LN2410SBC		LN2410SBC		725
+cb3rufc			MACH_CB3RUFC		CB3RUFC			726
+mp2usb			MACH_MP2USB		MP2USB			727
+ntnp425c		MACH_NTNP425C		NTNP425C		728
+colibri			MACH_COLIBRI		COLIBRI			729
+pcm7220			MACH_PCM7220		PCM7220			730
+gateway7001		MACH_GATEWAY7001	GATEWAY7001		731
+pcm027			MACH_PCM027		PCM027			732
+cmpxa			MACH_CMPXA		CMPXA			733
+anubis			MACH_ANUBIS		ANUBIS			734
+ite8152			MACH_ITE8152		ITE8152			735
+lpc3xxx			MACH_LPC3XXX		LPC3XXX			736
+puppeteer		MACH_PUPPETEER		PUPPETEER		737
+vt001			MACH_MACH_VADATECH	MACH_VADATECH		738
+e570			MACH_E570		E570			739
+x50			MACH_X50		X50			740
+recon			MACH_RECON		RECON			741
+xboardgp8		MACH_XBOARDGP8		XBOARDGP8		742
+fpic2			MACH_FPIC2		FPIC2			743
+akita			MACH_AKITA		AKITA			744
+a81			MACH_A81		A81			745
+svm_sc25x		MACH_SVM_SC25X		SVM_SC25X		746
+vt020			MACH_VADATECH020	VADATECH020		747
+tli			MACH_TLI		TLI			748
+edb9315lc		MACH_EDB9315LC		EDB9315LC		749
+passec			MACH_PASSEC		PASSEC			750
+ds_tiger		MACH_DS_TIGER		DS_TIGER		751
+e310			MACH_E310		E310			752
+e330			MACH_E330		E330			753
+rt3000			MACH_RT3000		RT3000			754
+nokia770		MACH_NOKIA770		NOKIA770		755
+pnx0106			MACH_PNX0106		PNX0106			756
+hx21xx			MACH_HX21XX		HX21XX			757
+faraday			MACH_FARADAY		FARADAY			758
+sbc9312			MACH_SBC9312		SBC9312			759
+batman			MACH_BATMAN		BATMAN			760
+jpd201			MACH_JPD201		JPD201			761
+mipsa			MACH_MIPSA		MIPSA			762
+kacom			MACH_KACOM		KACOM			763
+swarcocpu		MACH_SWARCOCPU		SWARCOCPU		764
+swarcodsl		MACH_SWARCODSL		SWARCODSL		765
+blueangel		MACH_BLUEANGEL		BLUEANGEL		766
+hairygrama		MACH_HAIRYGRAMA		HAIRYGRAMA		767
+banff			MACH_BANFF		BANFF			768
+carmeva			MACH_CARMEVA		CARMEVA			769
+sam255			MACH_SAM255		SAM255			770
+ppm10			MACH_PPM10		PPM10			771
+edb9315a		MACH_EDB9315A		EDB9315A		772
+sunset			MACH_SUNSET		SUNSET			773
+stargate2		MACH_STARGATE2		STARGATE2		774
+intelmote2		MACH_INTELMOTE2		INTELMOTE2		775
+trizeps4		MACH_TRIZEPS4		TRIZEPS4		776
+mainstone2		MACH_MAINSTONE2		MAINSTONE2		777
+ez_ixp42x		MACH_EZ_IXP42X		EZ_IXP42X		778
+tapwave_zodiac		MACH_TAPWAVE_ZODIAC	TAPWAVE_ZODIAC		779
+universalmeter		MACH_UNIVERSALMETER	UNIVERSALMETER		780
+hicoarm9		MACH_HICOARM9		HICOARM9		781
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 5f8cfa6..ba243a4 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -617,6 +617,33 @@
 }
 
 /*
+ * This function selects if the context switch from prev to next
+ * has to tweak the TSC disable bit in the cr4.
+ */
+static inline void disable_tsc(struct task_struct *prev_p,
+			       struct task_struct *next_p)
+{
+	struct thread_info *prev, *next;
+
+	/*
+	 * gcc should eliminate the ->thread_info dereference if
+	 * has_secure_computing returns 0 at compile time (SECCOMP=n).
+	 */
+	prev = prev_p->thread_info;
+	next = next_p->thread_info;
+
+	if (has_secure_computing(prev) || has_secure_computing(next)) {
+		/* slow path here */
+		if (has_secure_computing(prev) &&
+		    !has_secure_computing(next)) {
+			write_cr4(read_cr4() & ~X86_CR4_TSD);
+		} else if (!has_secure_computing(prev) &&
+			   has_secure_computing(next))
+			write_cr4(read_cr4() | X86_CR4_TSD);
+	}
+}
+
+/*
  *	switch_to(x,yn) should switch tasks from x to y.
  *
  * We fsave/fwait so that an exception goes off at the right time
@@ -695,6 +722,8 @@
 	if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr))
 		handle_io_bitmap(next, tss);
 
+	disable_tsc(prev_p, next_p);
+
 	return prev_p;
 }
 
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 442a6e9..3db9a04 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -289,3 +289,5 @@
 	.long sys_add_key
 	.long sys_request_key
 	.long sys_keyctl
+	.long sys_ioprio_set
+	.long sys_ioprio_get		/* 290 */
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index b1d5d3d..785a51b 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1577,8 +1577,8 @@
 	data8 sys_add_key
 	data8 sys_request_key
 	data8 sys_keyctl
-	data8 sys_ni_syscall
-	data8 sys_ni_syscall			// 1275
+	data8 sys_ioprio_set
+	data8 sys_ioprio_get			// 1275
 	data8 sys_set_zone_reclaim
 	data8 sys_ni_syscall
 	data8 sys_ni_syscall
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 508026a..65ee153 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -457,7 +457,7 @@
 	if (!user_mode(regs))
 		return 1;
 
-	if (try_to_freeze(0))
+	if (try_to_freeze())
 		goto no_signal;
 
 	if (!oldset)
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index b6a63a4..191a8de 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -1449,3 +1449,5 @@
 	.long sys_request_key		/* 270 */
 	.long sys_keyctl
 	.long sys_waitid
+	.long sys_ioprio_set
+	.long sys_ioprio_get
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 334ef41..6164a2b 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -606,9 +606,19 @@
 		struct page *page = pfn_to_page(pfn);
 		if (!PageReserved(page)
 		    && !test_bit(PG_arch_1, &page->flags)) {
-			if (vma->vm_mm == current->active_mm)
+			if (vma->vm_mm == current->active_mm) {
+#ifdef CONFIG_8xx
+			/* On 8xx, cache control instructions (particularly 
+		 	 * "dcbst" from flush_dcache_icache) fault as write 
+			 * operation if there is an unpopulated TLB entry 
+			 * for the address in question. To workaround that, 
+			 * we invalidate the TLB here, thus avoiding dcbst 
+			 * misbehaviour.
+			 */
+				_tlbie(address);
+#endif
 				__flush_dcache_icache((void *) address);
-			else
+			} else
 				flush_dcache_icache_page(page);
 			set_bit(PG_arch_1, &page->flags);
 		}
diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S
index f459ade..016a746 100644
--- a/arch/ppc/platforms/pmac_sleep.S
+++ b/arch/ppc/platforms/pmac_sleep.S
@@ -46,7 +46,7 @@
 	.section .text
 	.align	5
 
-#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC)
+#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
 
 /* This gets called by via-pmu.c late during the sleep process.
  * The PMU was already send the sleep command and will shut us down
@@ -382,7 +382,7 @@
 	isync
 	rfi
 
-#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */
+#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */
 
 	.section .data
 	.balign	L1_CACHE_LINE_SIZE
diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
index de60ccc..778ce4f 100644
--- a/arch/ppc/platforms/pmac_time.c
+++ b/arch/ppc/platforms/pmac_time.c
@@ -206,7 +206,7 @@
 	return 1;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * Reset the time after a sleep.
  */
@@ -238,7 +238,7 @@
 static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
 	time_sleep_notify, SLEEP_LEVEL_MISC,
 };
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 /*
  * Query the OF and get the decr frequency.
@@ -251,9 +251,9 @@
 	struct device_node *cpu;
 	unsigned int freq, *fp;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 	/* We assume MacRISC2 machines have correct device-tree
 	 * calibration. That's better since the VIA itself seems
diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c
index 70e58f4..8b149c2 100644
--- a/arch/ppc/platforms/sandpoint.c
+++ b/arch/ppc/platforms/sandpoint.c
@@ -324,6 +324,7 @@
 			pdata[1].irq = 0;
 			pdata[1].mapbase = 0;
 		}
+	}
 
 	printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n");
 	printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
index b45d826..ad39b86 100644
--- a/arch/ppc/syslib/open_pic.c
+++ b/arch/ppc/syslib/open_pic.c
@@ -370,8 +370,9 @@
 	/* Initialize IPI interrupts */
 	if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
 	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
-		/* Disabled, Priority 10..13 */
-		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
+		/* Disabled, increased priorities 10..13 */
+		openpic_initipi(i, OPENPIC_PRIORITY_IPI_BASE+i,
+				OPENPIC_VEC_IPI+i+offset);
 		/* IPIs are per-CPU */
 		irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
 		irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
@@ -399,8 +400,9 @@
 		if (sense & IRQ_SENSE_MASK)
 			irq_desc[i+offset].status = IRQ_LEVEL;
 
-		/* Enabled, Priority 8 */
-		openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
+		/* Enabled, Default priority */
+		openpic_initirq(i, OPENPIC_PRIORITY_DEFAULT, i+offset,
+				(sense & IRQ_POLARITY_MASK),
 				(sense & IRQ_SENSE_MASK));
 		/* Processor 0 */
 		openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
@@ -656,6 +658,18 @@
 }
 
 /*
+ * Change the priority of an interrupt
+ */
+void __init
+openpic_set_irq_priority(u_int irq, u_int pri)
+{
+	check_arg_irq(irq);
+	openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
+				OPENPIC_PRIORITY_MASK,
+				pri << OPENPIC_PRIORITY_SHIFT);
+}
+
+/*
  * Initalize the interrupt source which will generate an NMI.
  * This raises the interrupt's priority from 8 to 9.
  *
@@ -665,9 +679,7 @@
 openpic_init_nmi_irq(u_int irq)
 {
 	check_arg_irq(irq);
-	openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
-				OPENPIC_PRIORITY_MASK,
-				9 << OPENPIC_PRIORITY_SHIFT);
+	openpic_set_irq_priority(irq, OPENPIC_PRIORITY_NMI);
 }
 
 /*
diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
index b230a63..705742f 100644
--- a/arch/ppc64/kernel/ppc_ksyms.c
+++ b/arch/ppc64/kernel/ppc_ksyms.c
@@ -75,6 +75,7 @@
 EXPORT_SYMBOL(giveup_altivec);
 #endif
 EXPORT_SYMBOL(__flush_icache_range);
+EXPORT_SYMBOL(flush_dcache_range);
 
 #ifdef CONFIG_SMP
 #ifdef CONFIG_PPC_ISERIES
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
index 2348a75..2a532db 100644
--- a/arch/ppc64/kernel/time.c
+++ b/arch/ppc64/kernel/time.c
@@ -91,6 +91,7 @@
 unsigned      tb_to_us;
 unsigned long processor_freq;
 DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL_GPL(rtc_lock);
 
 unsigned long tb_to_ns_scale;
 unsigned long tb_to_ns_shift;
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 1d91271..7577f9d 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -482,6 +482,33 @@
 }
 
 /*
+ * This function selects if the context switch from prev to next
+ * has to tweak the TSC disable bit in the cr4.
+ */
+static inline void disable_tsc(struct task_struct *prev_p,
+			       struct task_struct *next_p)
+{
+	struct thread_info *prev, *next;
+
+	/*
+	 * gcc should eliminate the ->thread_info dereference if
+	 * has_secure_computing returns 0 at compile time (SECCOMP=n).
+	 */
+	prev = prev_p->thread_info;
+	next = next_p->thread_info;
+
+	if (has_secure_computing(prev) || has_secure_computing(next)) {
+		/* slow path here */
+		if (has_secure_computing(prev) &&
+		    !has_secure_computing(next)) {
+			write_cr4(read_cr4() & ~X86_CR4_TSD);
+		} else if (!has_secure_computing(prev) &&
+			   has_secure_computing(next))
+			write_cr4(read_cr4() | X86_CR4_TSD);
+	}
+}
+
+/*
  * This special macro can be used to load a debugging register
  */
 #define loaddebug(thread,r) set_debug(thread->debugreg ## r, r)
@@ -599,6 +626,8 @@
 		}
 	}
 
+	disable_tsc(prev_p, next_p);
+
 	return prev_p;
 }
 
diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c
index 3410b4d..91aeb67 100644
--- a/drivers/block/as-iosched.c
+++ b/drivers/block/as-iosched.c
@@ -1806,7 +1806,8 @@
 	rq->elevator_private = NULL;
 }
 
-static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+static int as_set_request(request_queue_t *q, struct request *rq,
+			  struct bio *bio, int gfp_mask)
 {
 	struct as_data *ad = q->elevator->elevator_data;
 	struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
@@ -1827,7 +1828,7 @@
 	return 1;
 }
 
-static int as_may_queue(request_queue_t *q, int rw)
+static int as_may_queue(request_queue_t *q, int rw, struct bio *bio)
 {
 	int ret = ELV_MQUEUE_MAY;
 	struct as_data *ad = q->elevator->elevator_data;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index abde270..653512b 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1,6 +1,6 @@
 /*
  *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
- *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P.
+ *    Copyright 2000, 2005 Hewlett-Packard Development Company, L.P.
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
@@ -54,7 +54,7 @@
 MODULE_AUTHOR("Hewlett-Packard Company");
 MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
-			" SA6i P600 P800 E400");
+			" SA6i P600 P800 E400 E300");
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -85,8 +85,10 @@
 		0x103C, 0x3225, 0, 0, 0},
 	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
 		0x103c, 0x3223, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
 		0x103c, 0x3231, 0, 0, 0},
+	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
+		0x103c, 0x3233, 0, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -110,6 +112,7 @@
 	{ 0x3225103C, "Smart Array P600", &SA5_access},
 	{ 0x3223103C, "Smart Array P800", &SA5_access},
 	{ 0x3231103C, "Smart Array E400", &SA5_access},
+	{ 0x3233103C, "Smart Array E300", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
@@ -635,6 +638,7 @@
 		cciss_pci_info_struct pciinfo;
 
 		if (!arg) return -EINVAL;
+		pciinfo.domain = pci_domain_nr(host->pdev->bus);
 		pciinfo.bus = host->pdev->bus->number;
 		pciinfo.dev_fn = host->pdev->devfn;
 		pciinfo.board_id = host->board_id;
@@ -787,13 +791,6 @@
  		luninfo.LunID = drv->LunID;
  		luninfo.num_opens = drv->usage_count;
  		luninfo.num_parts = 0;
- 		/* count partitions 1 to 15 with sizes > 0 */
- 		for (i = 0; i < MAX_PART - 1; i++) {
-			if (!disk->part[i])
-				continue;
-			if (disk->part[i]->nr_sects != 0)
-				luninfo.num_parts++;
-		}
  		if (copy_to_user(argp, &luninfo,
  				sizeof(LogvolInfo_struct)))
  			return -EFAULT;
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c
index 3ac47dd..ff1cc96 100644
--- a/drivers/block/cfq-iosched.c
+++ b/drivers/block/cfq-iosched.c
@@ -21,22 +21,34 @@
 #include <linux/hash.h>
 #include <linux/rbtree.h>
 #include <linux/mempool.h>
-
-static unsigned long max_elapsed_crq;
-static unsigned long max_elapsed_dispatch;
+#include <linux/ioprio.h>
+#include <linux/writeback.h>
 
 /*
  * tunables
  */
 static int cfq_quantum = 4;		/* max queue in one round of service */
 static int cfq_queued = 8;		/* minimum rq allocate limit per-queue*/
-static int cfq_service = HZ;		/* period over which service is avg */
-static int cfq_fifo_expire_r = HZ / 2;	/* fifo timeout for sync requests */
-static int cfq_fifo_expire_w = 5 * HZ;	/* fifo timeout for async requests */
-static int cfq_fifo_rate = HZ / 8;	/* fifo expiry rate */
+static int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
 static int cfq_back_max = 16 * 1024;	/* maximum backwards seek, in KiB */
 static int cfq_back_penalty = 2;	/* penalty of a backwards seek */
 
+static int cfq_slice_sync = HZ / 10;
+static int cfq_slice_async = HZ / 25;
+static int cfq_slice_async_rq = 2;
+static int cfq_slice_idle = HZ / 100;
+
+#define CFQ_IDLE_GRACE		(HZ / 10)
+#define CFQ_SLICE_SCALE		(5)
+
+#define CFQ_KEY_ASYNC		(0)
+#define CFQ_KEY_ANY		(0xffff)
+
+/*
+ * disable queueing at the driver/hardware level
+ */
+static int cfq_max_depth = 1;
+
 /*
  * for the hash of cfqq inside the cfqd
  */
@@ -55,6 +67,7 @@
 #define list_entry_hash(ptr)	hlist_entry((ptr), struct cfq_rq, hash)
 
 #define list_entry_cfqq(ptr)	list_entry((ptr), struct cfq_queue, cfq_list)
+#define list_entry_fifo(ptr)	list_entry((ptr), struct request, queuelist)
 
 #define RQ_DATA(rq)		(rq)->elevator_private
 
@@ -75,78 +88,110 @@
 #define rb_entry_crq(node)	rb_entry((node), struct cfq_rq, rb_node)
 #define rq_rb_key(rq)		(rq)->sector
 
-/*
- * threshold for switching off non-tag accounting
- */
-#define CFQ_MAX_TAG		(4)
-
-/*
- * sort key types and names
- */
-enum {
-	CFQ_KEY_PGID,
-	CFQ_KEY_TGID,
-	CFQ_KEY_UID,
-	CFQ_KEY_GID,
-	CFQ_KEY_LAST,
-};
-
-static char *cfq_key_types[] = { "pgid", "tgid", "uid", "gid", NULL };
-
 static kmem_cache_t *crq_pool;
 static kmem_cache_t *cfq_pool;
 static kmem_cache_t *cfq_ioc_pool;
 
+#define CFQ_PRIO_LISTS		IOPRIO_BE_NR
+#define cfq_class_idle(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
+#define cfq_class_be(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_BE)
+#define cfq_class_rt(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
+
+#define ASYNC			(0)
+#define SYNC			(1)
+
+#define cfq_cfqq_dispatched(cfqq)	\
+	((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC])
+
+#define cfq_cfqq_class_sync(cfqq)	((cfqq)->key != CFQ_KEY_ASYNC)
+
+#define cfq_cfqq_sync(cfqq)		\
+	(cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
+
+/*
+ * Per block device queue structure
+ */
 struct cfq_data {
-	struct list_head rr_list;
+	atomic_t ref;
+	request_queue_t *queue;
+
+	/*
+	 * rr list of queues with requests and the count of them
+	 */
+	struct list_head rr_list[CFQ_PRIO_LISTS];
+	struct list_head busy_rr;
+	struct list_head cur_rr;
+	struct list_head idle_rr;
+	unsigned int busy_queues;
+
+	/*
+	 * non-ordered list of empty cfqq's
+	 */
 	struct list_head empty_list;
 
+	/*
+	 * cfqq lookup hash
+	 */
 	struct hlist_head *cfq_hash;
-	struct hlist_head *crq_hash;
 
-	/* queues on rr_list (ie they have pending requests */
-	unsigned int busy_queues;
+	/*
+	 * global crq hash for all queues
+	 */
+	struct hlist_head *crq_hash;
 
 	unsigned int max_queued;
 
-	atomic_t ref;
-
-	int key_type;
-
 	mempool_t *crq_pool;
 
-	request_queue_t *queue;
+	int rq_in_driver;
+
+	/*
+	 * schedule slice state info
+	 */
+	/*
+	 * idle window management
+	 */
+	struct timer_list idle_slice_timer;
+	struct work_struct unplug_work;
+
+	struct cfq_queue *active_queue;
+	struct cfq_io_context *active_cic;
+	int cur_prio, cur_end_prio;
+	unsigned int dispatch_slice;
+
+	struct timer_list idle_class_timer;
 
 	sector_t last_sector;
+	unsigned long last_end_request;
 
-	int rq_in_driver;
+	unsigned int rq_starved;
 
 	/*
 	 * tunables, see top of file
 	 */
 	unsigned int cfq_quantum;
 	unsigned int cfq_queued;
-	unsigned int cfq_fifo_expire_r;
-	unsigned int cfq_fifo_expire_w;
-	unsigned int cfq_fifo_batch_expire;
+	unsigned int cfq_fifo_expire[2];
 	unsigned int cfq_back_penalty;
 	unsigned int cfq_back_max;
-	unsigned int find_best_crq;
-
-	unsigned int cfq_tagged;
+	unsigned int cfq_slice[2];
+	unsigned int cfq_slice_async_rq;
+	unsigned int cfq_slice_idle;
+	unsigned int cfq_max_depth;
 };
 
+/*
+ * Per process-grouping structure
+ */
 struct cfq_queue {
 	/* reference count */
 	atomic_t ref;
 	/* parent cfq_data */
 	struct cfq_data *cfqd;
-	/* hash of mergeable requests */
+	/* cfqq lookup hash */
 	struct hlist_node cfq_hash;
 	/* hash key */
-	unsigned long key;
-	/* whether queue is on rr (or empty) list */
-	int on_rr;
+	unsigned int key;
 	/* on either rr or empty list of cfqd */
 	struct list_head cfq_list;
 	/* sorted list of pending requests */
@@ -158,21 +203,22 @@
 	/* currently allocated requests */
 	int allocated[2];
 	/* fifo list of requests in sort_list */
-	struct list_head fifo[2];
-	/* last time fifo expired */
-	unsigned long last_fifo_expire;
+	struct list_head fifo;
 
-	int key_type;
+	unsigned long slice_start;
+	unsigned long slice_end;
+	unsigned long slice_left;
+	unsigned long service_last;
 
-	unsigned long service_start;
-	unsigned long service_used;
+	/* number of requests that are on the dispatch list */
+	int on_dispatch[2];
 
-	unsigned int max_rate;
+	/* io prio of this group */
+	unsigned short ioprio, org_ioprio;
+	unsigned short ioprio_class, org_ioprio_class;
 
-	/* number of requests that have been handed to the driver */
-	int in_flight;
-	/* number of currently allocated requests */
-	int alloc_limit[2];
+	/* various state flags, see below */
+	unsigned int flags;
 };
 
 struct cfq_rq {
@@ -184,43 +230,80 @@
 	struct cfq_queue *cfq_queue;
 	struct cfq_io_context *io_context;
 
-	unsigned long service_start;
-	unsigned long queue_start;
-
-	unsigned int in_flight : 1;
-	unsigned int accounted : 1;
-	unsigned int is_sync   : 1;
-	unsigned int is_write  : 1;
+	unsigned int crq_flags;
 };
 
-static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned long);
-static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *);
-static void cfq_update_next_crq(struct cfq_rq *);
-static void cfq_put_cfqd(struct cfq_data *cfqd);
+enum cfqq_state_flags {
+	CFQ_CFQQ_FLAG_on_rr = 0,
+	CFQ_CFQQ_FLAG_wait_request,
+	CFQ_CFQQ_FLAG_must_alloc,
+	CFQ_CFQQ_FLAG_must_alloc_slice,
+	CFQ_CFQQ_FLAG_must_dispatch,
+	CFQ_CFQQ_FLAG_fifo_expire,
+	CFQ_CFQQ_FLAG_idle_window,
+	CFQ_CFQQ_FLAG_prio_changed,
+	CFQ_CFQQ_FLAG_expired,
+};
 
-/*
- * what the fairness is based on (ie how processes are grouped and
- * differentiated)
- */
-static inline unsigned long
-cfq_hash_key(struct cfq_data *cfqd, struct task_struct *tsk)
-{
-	/*
-	 * optimize this so that ->key_type is the offset into the struct
-	 */
-	switch (cfqd->key_type) {
-		case CFQ_KEY_PGID:
-			return process_group(tsk);
-		default:
-		case CFQ_KEY_TGID:
-			return tsk->tgid;
-		case CFQ_KEY_UID:
-			return tsk->uid;
-		case CFQ_KEY_GID:
-			return tsk->gid;
-	}
+#define CFQ_CFQQ_FNS(name)						\
+static inline void cfq_mark_cfqq_##name(struct cfq_queue *cfqq)		\
+{									\
+	cfqq->flags |= (1 << CFQ_CFQQ_FLAG_##name);			\
+}									\
+static inline void cfq_clear_cfqq_##name(struct cfq_queue *cfqq)	\
+{									\
+	cfqq->flags &= ~(1 << CFQ_CFQQ_FLAG_##name);			\
+}									\
+static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq)		\
+{									\
+	return (cfqq->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0;	\
 }
 
+CFQ_CFQQ_FNS(on_rr);
+CFQ_CFQQ_FNS(wait_request);
+CFQ_CFQQ_FNS(must_alloc);
+CFQ_CFQQ_FNS(must_alloc_slice);
+CFQ_CFQQ_FNS(must_dispatch);
+CFQ_CFQQ_FNS(fifo_expire);
+CFQ_CFQQ_FNS(idle_window);
+CFQ_CFQQ_FNS(prio_changed);
+CFQ_CFQQ_FNS(expired);
+#undef CFQ_CFQQ_FNS
+
+enum cfq_rq_state_flags {
+	CFQ_CRQ_FLAG_in_flight = 0,
+	CFQ_CRQ_FLAG_in_driver,
+	CFQ_CRQ_FLAG_is_sync,
+	CFQ_CRQ_FLAG_requeued,
+};
+
+#define CFQ_CRQ_FNS(name)						\
+static inline void cfq_mark_crq_##name(struct cfq_rq *crq)		\
+{									\
+	crq->crq_flags |= (1 << CFQ_CRQ_FLAG_##name);			\
+}									\
+static inline void cfq_clear_crq_##name(struct cfq_rq *crq)		\
+{									\
+	crq->crq_flags &= ~(1 << CFQ_CRQ_FLAG_##name);			\
+}									\
+static inline int cfq_crq_##name(const struct cfq_rq *crq)		\
+{									\
+	return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0;	\
+}
+
+CFQ_CRQ_FNS(in_flight);
+CFQ_CRQ_FNS(in_driver);
+CFQ_CRQ_FNS(is_sync);
+CFQ_CRQ_FNS(requeued);
+#undef CFQ_CRQ_FNS
+
+static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
+static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *);
+static void cfq_put_cfqd(struct cfq_data *cfqd);
+static inline int cfq_pending_requests(struct cfq_data *cfqd);
+
+#define process_sync(tsk)	((tsk)->flags & PF_SYNCWRITE)
+
 /*
  * lots of deadline iosched dupes, can be abstracted later...
  */
@@ -235,16 +318,12 @@
 
 	if (q->last_merge == crq->request)
 		q->last_merge = NULL;
-
-	cfq_update_next_crq(crq);
 }
 
 static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
 {
 	const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request));
 
-	BUG_ON(!hlist_unhashed(&crq->hash));
-
 	hlist_add_head(&crq->hash, &cfqd->crq_hash[hash_idx]);
 }
 
@@ -257,8 +336,6 @@
 		struct cfq_rq *crq = list_entry_hash(entry);
 		struct request *__rq = crq->request;
 
-		BUG_ON(hlist_unhashed(&crq->hash));
-
 		if (!rq_mergeable(__rq)) {
 			cfq_del_crq_hash(crq);
 			continue;
@@ -287,36 +364,16 @@
 		return crq2;
 	if (crq2 == NULL)
 		return crq1;
+	if (cfq_crq_requeued(crq1))
+		return crq1;
+	if (cfq_crq_requeued(crq2))
+		return crq2;
 
 	s1 = crq1->request->sector;
 	s2 = crq2->request->sector;
 
 	last = cfqd->last_sector;
 
-#if 0
-	if (!list_empty(&cfqd->queue->queue_head)) {
-		struct list_head *entry = &cfqd->queue->queue_head;
-		unsigned long distance = ~0UL;
-		struct request *rq;
-
-		while ((entry = entry->prev) != &cfqd->queue->queue_head) {
-			rq = list_entry_rq(entry);
-
-			if (blk_barrier_rq(rq))
-				break;
-
-			if (distance < abs(s1 - rq->sector + rq->nr_sectors)) {
-				distance = abs(s1 - rq->sector +rq->nr_sectors);
-				last = rq->sector + rq->nr_sectors;
-			}
-			if (distance < abs(s2 - rq->sector + rq->nr_sectors)) {
-				distance = abs(s2 - rq->sector +rq->nr_sectors);
-				last = rq->sector + rq->nr_sectors;
-			}
-		}
-	}
-#endif
-
 	/*
 	 * by definition, 1KiB is 2 sectors
 	 */
@@ -377,11 +434,14 @@
 	struct cfq_rq *crq_next = NULL, *crq_prev = NULL;
 	struct rb_node *rbnext, *rbprev;
 
-	if (!ON_RB(&last->rb_node))
-		return NULL;
-
-	if ((rbnext = rb_next(&last->rb_node)) == NULL)
+	rbnext = NULL;
+	if (ON_RB(&last->rb_node))
+		rbnext = rb_next(&last->rb_node);
+	if (!rbnext) {
 		rbnext = rb_first(&cfqq->sort_list);
+		if (rbnext == &last->rb_node)
+			rbnext = NULL;
+	}
 
 	rbprev = rb_prev(&last->rb_node);
 
@@ -401,67 +461,53 @@
 		cfqq->next_crq = cfq_find_next_crq(cfqq->cfqd, cfqq, crq);
 }
 
-static int cfq_check_sort_rr_list(struct cfq_queue *cfqq)
+static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
 {
-	struct list_head *head = &cfqq->cfqd->rr_list;
-	struct list_head *next, *prev;
+	struct cfq_data *cfqd = cfqq->cfqd;
+	struct list_head *list, *entry;
 
-	/*
-	 * list might still be ordered
-	 */
-	next = cfqq->cfq_list.next;
-	if (next != head) {
-		struct cfq_queue *cnext = list_entry_cfqq(next);
-
-		if (cfqq->service_used > cnext->service_used)
-			return 1;
-	}
-
-	prev = cfqq->cfq_list.prev;
-	if (prev != head) {
-		struct cfq_queue *cprev = list_entry_cfqq(prev);
-
-		if (cfqq->service_used < cprev->service_used)
-			return 1;
-	}
-
-	return 0;
-}
-
-static void cfq_sort_rr_list(struct cfq_queue *cfqq, int new_queue)
-{
-	struct list_head *entry = &cfqq->cfqd->rr_list;
-
-	if (!cfqq->on_rr)
-		return;
-	if (!new_queue && !cfq_check_sort_rr_list(cfqq))
-		return;
+	BUG_ON(!cfq_cfqq_on_rr(cfqq));
 
 	list_del(&cfqq->cfq_list);
 
+	if (cfq_class_rt(cfqq))
+		list = &cfqd->cur_rr;
+	else if (cfq_class_idle(cfqq))
+		list = &cfqd->idle_rr;
+	else {
+		/*
+		 * if cfqq has requests in flight, don't allow it to be
+		 * found in cfq_set_active_queue before it has finished them.
+		 * this is done to increase fairness between a process that
+		 * has lots of io pending vs one that only generates one
+		 * sporadically or synchronously
+		 */
+		if (cfq_cfqq_dispatched(cfqq))
+			list = &cfqd->busy_rr;
+		else
+			list = &cfqd->rr_list[cfqq->ioprio];
+	}
+
 	/*
-	 * sort by our mean service_used, sub-sort by in-flight requests
+	 * if queue was preempted, just add to front to be fair. busy_rr
+	 * isn't sorted.
 	 */
-	while ((entry = entry->prev) != &cfqq->cfqd->rr_list) {
+	if (preempted || list == &cfqd->busy_rr) {
+		list_add(&cfqq->cfq_list, list);
+		return;
+	}
+
+	/*
+	 * sort by when queue was last serviced
+	 */
+	entry = list;
+	while ((entry = entry->prev) != list) {
 		struct cfq_queue *__cfqq = list_entry_cfqq(entry);
 
-		if (cfqq->service_used > __cfqq->service_used)
+		if (!__cfqq->service_last)
 			break;
-		else if (cfqq->service_used == __cfqq->service_used) {
-			struct list_head *prv;
-
-			while ((prv = entry->prev) != &cfqq->cfqd->rr_list) {
-				__cfqq = list_entry_cfqq(prv);
-
-				WARN_ON(__cfqq->service_used > cfqq->service_used);
-				if (cfqq->service_used != __cfqq->service_used)
-					break;
-				if (cfqq->in_flight > __cfqq->in_flight)
-					break;
-
-				entry = prv;
-			}
-		}
+		if (time_before(__cfqq->service_last, cfqq->service_last))
+			break;
 	}
 
 	list_add(&cfqq->cfq_list, entry);
@@ -469,28 +515,24 @@
 
 /*
  * add to busy list of queues for service, trying to be fair in ordering
- * the pending list according to requests serviced
+ * the pending list according to last request service
  */
 static inline void
-cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue)
 {
-	/*
-	 * it's currently on the empty list
-	 */
-	cfqq->on_rr = 1;
+	BUG_ON(cfq_cfqq_on_rr(cfqq));
+	cfq_mark_cfqq_on_rr(cfqq);
 	cfqd->busy_queues++;
 
-	if (time_after(jiffies, cfqq->service_start + cfq_service))
-		cfqq->service_used >>= 3;
-
-	cfq_sort_rr_list(cfqq, 1);
+	cfq_resort_rr_list(cfqq, requeue);
 }
 
 static inline void
 cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
+	BUG_ON(!cfq_cfqq_on_rr(cfqq));
+	cfq_clear_cfqq_on_rr(cfqq);
 	list_move(&cfqq->cfq_list, &cfqd->empty_list);
-	cfqq->on_rr = 0;
 
 	BUG_ON(!cfqd->busy_queues);
 	cfqd->busy_queues--;
@@ -505,16 +547,17 @@
 
 	if (ON_RB(&crq->rb_node)) {
 		struct cfq_data *cfqd = cfqq->cfqd;
+		const int sync = cfq_crq_is_sync(crq);
 
-		BUG_ON(!cfqq->queued[crq->is_sync]);
+		BUG_ON(!cfqq->queued[sync]);
+		cfqq->queued[sync]--;
 
 		cfq_update_next_crq(crq);
 
-		cfqq->queued[crq->is_sync]--;
 		rb_erase(&crq->rb_node, &cfqq->sort_list);
 		RB_CLEAR_COLOR(&crq->rb_node);
 
-		if (RB_EMPTY(&cfqq->sort_list) && cfqq->on_rr)
+		if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list))
 			cfq_del_cfqq_rr(cfqd, cfqq);
 	}
 }
@@ -550,7 +593,7 @@
 	struct cfq_rq *__alias;
 
 	crq->rb_key = rq_rb_key(rq);
-	cfqq->queued[crq->is_sync]++;
+	cfqq->queued[cfq_crq_is_sync(crq)]++;
 
 	/*
 	 * looks a little odd, but the first insert might return an alias.
@@ -561,8 +604,8 @@
 
 	rb_insert_color(&crq->rb_node, &cfqq->sort_list);
 
-	if (!cfqq->on_rr)
-		cfq_add_cfqq_rr(cfqd, cfqq);
+	if (!cfq_cfqq_on_rr(cfqq))
+		cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq));
 
 	/*
 	 * check if this request is a better next-serve candidate
@@ -575,17 +618,16 @@
 {
 	if (ON_RB(&crq->rb_node)) {
 		rb_erase(&crq->rb_node, &cfqq->sort_list);
-		cfqq->queued[crq->is_sync]--;
+		cfqq->queued[cfq_crq_is_sync(crq)]--;
 	}
 
 	cfq_add_crq_rb(crq);
 }
 
-static struct request *
-cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+
 {
-	const unsigned long key = cfq_hash_key(cfqd, current);
-	struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, key);
+	struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->pid, CFQ_KEY_ANY);
 	struct rb_node *n;
 
 	if (!cfqq)
@@ -609,20 +651,25 @@
 
 static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
 {
+	struct cfq_data *cfqd = q->elevator->elevator_data;
 	struct cfq_rq *crq = RQ_DATA(rq);
 
 	if (crq) {
 		struct cfq_queue *cfqq = crq->cfq_queue;
 
-		if (cfqq->cfqd->cfq_tagged) {
-			cfqq->service_used--;
-			cfq_sort_rr_list(cfqq, 0);
+		if (cfq_crq_in_driver(crq)) {
+			cfq_clear_crq_in_driver(crq);
+			WARN_ON(!cfqd->rq_in_driver);
+			cfqd->rq_in_driver--;
 		}
+		if (cfq_crq_in_flight(crq)) {
+			const int sync = cfq_crq_is_sync(crq);
 
-		if (crq->accounted) {
-			crq->accounted = 0;
-			cfqq->cfqd->rq_in_driver--;
+			cfq_clear_crq_in_flight(crq);
+			WARN_ON(!cfqq->on_dispatch[sync]);
+			cfqq->on_dispatch[sync]--;
 		}
+		cfq_mark_crq_requeued(crq);
 	}
 }
 
@@ -640,11 +687,10 @@
 	struct cfq_rq *crq = RQ_DATA(rq);
 
 	if (crq) {
-		cfq_remove_merge_hints(q, crq);
 		list_del_init(&rq->queuelist);
+		cfq_del_crq_rb(crq);
+		cfq_remove_merge_hints(q, crq);
 
-		if (crq->cfq_queue)
-			cfq_del_crq_rb(crq);
 	}
 }
 
@@ -662,21 +708,15 @@
 	}
 
 	__rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
-	if (__rq) {
-		BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
-
-		if (elv_rq_merge_ok(__rq, bio)) {
-			ret = ELEVATOR_BACK_MERGE;
-			goto out;
-		}
+	if (__rq && elv_rq_merge_ok(__rq, bio)) {
+		ret = ELEVATOR_BACK_MERGE;
+		goto out;
 	}
 
 	__rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
-	if (__rq) {
-		if (elv_rq_merge_ok(__rq, bio)) {
-			ret = ELEVATOR_FRONT_MERGE;
-			goto out;
-		}
+	if (__rq && elv_rq_merge_ok(__rq, bio)) {
+		ret = ELEVATOR_FRONT_MERGE;
+		goto out;
 	}
 
 	return ELEVATOR_NO_MERGE;
@@ -709,20 +749,220 @@
 cfq_merged_requests(request_queue_t *q, struct request *rq,
 		    struct request *next)
 {
-	struct cfq_rq *crq = RQ_DATA(rq);
-	struct cfq_rq *cnext = RQ_DATA(next);
-
 	cfq_merged_request(q, rq);
 
-	if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) {
-		if (time_before(cnext->queue_start, crq->queue_start)) {
-			list_move(&rq->queuelist, &next->queuelist);
-			crq->queue_start = cnext->queue_start;
-		}
+	/*
+	 * reposition in fifo if next is older than rq
+	 */
+	if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) &&
+	    time_before(next->start_time, rq->start_time))
+		list_move(&rq->queuelist, &next->queuelist);
+
+	cfq_remove_request(q, next);
+}
+
+static inline void
+__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	if (cfqq) {
+		/*
+		 * stop potential idle class queues waiting service
+		 */
+		del_timer(&cfqd->idle_class_timer);
+
+		cfqq->slice_start = jiffies;
+		cfqq->slice_end = 0;
+		cfqq->slice_left = 0;
+		cfq_clear_cfqq_must_alloc_slice(cfqq);
+		cfq_clear_cfqq_fifo_expire(cfqq);
+		cfq_clear_cfqq_expired(cfqq);
 	}
 
-	cfq_update_next_crq(cnext);
-	cfq_remove_request(q, next);
+	cfqd->active_queue = cfqq;
+}
+
+/*
+ * 0
+ * 0,1
+ * 0,1,2
+ * 0,1,2,3
+ * 0,1,2,3,4
+ * 0,1,2,3,4,5
+ * 0,1,2,3,4,5,6
+ * 0,1,2,3,4,5,6,7
+ */
+static int cfq_get_next_prio_level(struct cfq_data *cfqd)
+{
+	int prio, wrap;
+
+	prio = -1;
+	wrap = 0;
+	do {
+		int p;
+
+		for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
+			if (!list_empty(&cfqd->rr_list[p])) {
+				prio = p;
+				break;
+			}
+		}
+
+		if (prio != -1)
+			break;
+		cfqd->cur_prio = 0;
+		if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
+			cfqd->cur_end_prio = 0;
+			if (wrap)
+				break;
+			wrap = 1;
+		}
+	} while (1);
+
+	if (unlikely(prio == -1))
+		return -1;
+
+	BUG_ON(prio >= CFQ_PRIO_LISTS);
+
+	list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
+
+	cfqd->cur_prio = prio + 1;
+	if (cfqd->cur_prio > cfqd->cur_end_prio) {
+		cfqd->cur_end_prio = cfqd->cur_prio;
+		cfqd->cur_prio = 0;
+	}
+	if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
+		cfqd->cur_prio = 0;
+		cfqd->cur_end_prio = 0;
+	}
+
+	return prio;
+}
+
+static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+{
+	struct cfq_queue *cfqq;
+
+	/*
+	 * if current queue is expired but not done with its requests yet,
+	 * wait for that to happen
+	 */
+	if ((cfqq = cfqd->active_queue) != NULL) {
+		if (cfq_cfqq_expired(cfqq) && cfq_cfqq_dispatched(cfqq))
+			return NULL;
+	}
+
+	/*
+	 * if current list is non-empty, grab first entry. if it is empty,
+	 * get next prio level and grab first entry then if any are spliced
+	 */
+	if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1)
+		cfqq = list_entry_cfqq(cfqd->cur_rr.next);
+
+	/*
+	 * if we have idle queues and no rt or be queues had pending
+	 * requests, either allow immediate service if the grace period
+	 * has passed or arm the idle grace timer
+	 */
+	if (!cfqq && !list_empty(&cfqd->idle_rr)) {
+		unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+
+		if (time_after_eq(jiffies, end))
+			cfqq = list_entry_cfqq(cfqd->idle_rr.next);
+		else
+			mod_timer(&cfqd->idle_class_timer, end);
+	}
+
+	__cfq_set_active_queue(cfqd, cfqq);
+	return cfqq;
+}
+
+/*
+ * current cfqq expired its slice (or was too idle), select new one
+ */
+static void
+__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+		    int preempted)
+{
+	unsigned long now = jiffies;
+
+	if (cfq_cfqq_wait_request(cfqq))
+		del_timer(&cfqd->idle_slice_timer);
+
+	if (!preempted && !cfq_cfqq_dispatched(cfqq))
+		cfqq->service_last = now;
+
+	cfq_clear_cfqq_must_dispatch(cfqq);
+	cfq_clear_cfqq_wait_request(cfqq);
+
+	/*
+	 * store what was left of this slice, if the queue idled out
+	 * or was preempted
+	 */
+	if (time_after(now, cfqq->slice_end))
+		cfqq->slice_left = now - cfqq->slice_end;
+	else
+		cfqq->slice_left = 0;
+
+	if (cfq_cfqq_on_rr(cfqq))
+		cfq_resort_rr_list(cfqq, preempted);
+
+	if (cfqq == cfqd->active_queue)
+		cfqd->active_queue = NULL;
+
+	if (cfqd->active_cic) {
+		put_io_context(cfqd->active_cic->ioc);
+		cfqd->active_cic = NULL;
+	}
+
+	cfqd->dispatch_slice = 0;
+}
+
+static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted)
+{
+	struct cfq_queue *cfqq = cfqd->active_queue;
+
+	if (cfqq) {
+		/*
+		 * use deferred expiry, if there are requests in progress as
+		 * not to disturb the slice of the next queue
+		 */
+		if (cfq_cfqq_dispatched(cfqq))
+			cfq_mark_cfqq_expired(cfqq);
+		else
+			__cfq_slice_expired(cfqd, cfqq, preempted);
+	}
+}
+
+static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+
+{
+	WARN_ON(!RB_EMPTY(&cfqq->sort_list));
+	WARN_ON(cfqq != cfqd->active_queue);
+
+	/*
+	 * idle is disabled, either manually or by past process history
+	 */
+	if (!cfqd->cfq_slice_idle)
+		return 0;
+	if (!cfq_cfqq_idle_window(cfqq))
+		return 0;
+	/*
+	 * task has exited, don't wait
+	 */
+	if (cfqd->active_cic && !cfqd->active_cic->ioc->task)
+		return 0;
+
+	cfq_mark_cfqq_must_dispatch(cfqq);
+	cfq_mark_cfqq_wait_request(cfqq);
+
+	if (!timer_pending(&cfqd->idle_slice_timer)) {
+		unsigned long slice_left = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
+
+		cfqd->idle_slice_timer.expires = jiffies + slice_left;
+		add_timer(&cfqd->idle_slice_timer);
+	}
+
+	return 1;
 }
 
 /*
@@ -738,31 +978,40 @@
 	struct request *__rq;
 	sector_t last;
 
-	cfq_del_crq_rb(crq);
-	cfq_remove_merge_hints(q, crq);
 	list_del(&crq->request->queuelist);
 
 	last = cfqd->last_sector;
-	while ((entry = entry->prev) != head) {
-		__rq = list_entry_rq(entry);
+	list_for_each_entry_reverse(__rq, head, queuelist) {
+		struct cfq_rq *__crq = RQ_DATA(__rq);
 
-		if (blk_barrier_rq(crq->request))
+		if (blk_barrier_rq(__rq))
 			break;
-		if (!blk_fs_request(crq->request))
+		if (!blk_fs_request(__rq))
+			break;
+		if (cfq_crq_requeued(__crq))
 			break;
 
-		if (crq->request->sector > __rq->sector)
+		if (__rq->sector <= crq->request->sector)
 			break;
 		if (__rq->sector > last && crq->request->sector < last) {
-			last = crq->request->sector;
+			last = crq->request->sector + crq->request->nr_sectors;
 			break;
 		}
+		entry = &__rq->queuelist;
 	}
 
 	cfqd->last_sector = last;
-	crq->in_flight = 1;
-	cfqq->in_flight++;
-	list_add(&crq->request->queuelist, entry);
+
+	cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq);
+
+	cfq_del_crq_rb(crq);
+	cfq_remove_merge_hints(q, crq);
+
+	cfq_mark_crq_in_flight(crq);
+	cfq_clear_crq_requeued(crq);
+
+	cfqq->on_dispatch[cfq_crq_is_sync(crq)]++;
+	list_add_tail(&crq->request->queuelist, entry);
 }
 
 /*
@@ -771,173 +1020,235 @@
 static inline struct cfq_rq *cfq_check_fifo(struct cfq_queue *cfqq)
 {
 	struct cfq_data *cfqd = cfqq->cfqd;
-	const int reads = !list_empty(&cfqq->fifo[0]);
-	const int writes = !list_empty(&cfqq->fifo[1]);
-	unsigned long now = jiffies;
+	struct request *rq;
 	struct cfq_rq *crq;
 
-	if (time_before(now, cfqq->last_fifo_expire + cfqd->cfq_fifo_batch_expire))
+	if (cfq_cfqq_fifo_expire(cfqq))
 		return NULL;
 
-	crq = RQ_DATA(list_entry(cfqq->fifo[0].next, struct request, queuelist));
-	if (reads && time_after(now, crq->queue_start + cfqd->cfq_fifo_expire_r)) {
-		cfqq->last_fifo_expire = now;
-		return crq;
-	}
+	if (!list_empty(&cfqq->fifo)) {
+		int fifo = cfq_cfqq_class_sync(cfqq);
 
-	crq = RQ_DATA(list_entry(cfqq->fifo[1].next, struct request, queuelist));
-	if (writes && time_after(now, crq->queue_start + cfqd->cfq_fifo_expire_w)) {
-		cfqq->last_fifo_expire = now;
-		return crq;
+		crq = RQ_DATA(list_entry_fifo(cfqq->fifo.next));
+		rq = crq->request;
+		if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) {
+			cfq_mark_cfqq_fifo_expire(cfqq);
+			return crq;
+		}
 	}
 
 	return NULL;
 }
 
 /*
- * dispatch a single request from given queue
+ * Scale schedule slice based on io priority. Use the sync time slice only
+ * if a queue is marked sync and has sync io queued. A sync queue with async
+ * io only, should not get full sync slice length.
  */
-static inline void
-cfq_dispatch_request(request_queue_t *q, struct cfq_data *cfqd,
-		     struct cfq_queue *cfqq)
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-	struct cfq_rq *crq;
+	const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
 
-	/*
-	 * follow expired path, else get first next available
-	 */
-	if ((crq = cfq_check_fifo(cfqq)) == NULL) {
-		if (cfqd->find_best_crq)
-			crq = cfqq->next_crq;
-		else
-			crq = rb_entry_crq(rb_first(&cfqq->sort_list));
-	}
+	WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
 
-	cfqd->last_sector = crq->request->sector + crq->request->nr_sectors;
-
-	/*
-	 * finally, insert request into driver list
-	 */
-	cfq_dispatch_sort(q, crq);
+	return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
 }
 
-static int cfq_dispatch_requests(request_queue_t *q, int max_dispatch)
+static inline void
+cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
+}
+
+static inline int
+cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	const int base_rq = cfqd->cfq_slice_async_rq;
+
+	WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+
+	return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
+}
+
+/*
+ * scheduler run of queue, if there are requests pending and no one in the
+ * driver that will restart queueing
+ */
+static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
+{
+	if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd))
+		kblockd_schedule_work(&cfqd->unplug_work);
+}
+
+/*
+ * get next queue for service
+ */
+static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force)
+{
+	unsigned long now = jiffies;
+	struct cfq_queue *cfqq;
+
+	cfqq = cfqd->active_queue;
+	if (!cfqq)
+		goto new_queue;
+
+	if (cfq_cfqq_expired(cfqq))
+		goto new_queue;
+
+	/*
+	 * slice has expired
+	 */
+	if (!cfq_cfqq_must_dispatch(cfqq) && time_after(now, cfqq->slice_end))
+		goto expire;
+
+	/*
+	 * if queue has requests, dispatch one. if not, check if
+	 * enough slice is left to wait for one
+	 */
+	if (!RB_EMPTY(&cfqq->sort_list))
+		goto keep_queue;
+	else if (!force && cfq_cfqq_class_sync(cfqq) &&
+		 time_before(now, cfqq->slice_end)) {
+		if (cfq_arm_slice_timer(cfqd, cfqq))
+			return NULL;
+	}
+
+expire:
+	cfq_slice_expired(cfqd, 0);
+new_queue:
+	cfqq = cfq_set_active_queue(cfqd);
+keep_queue:
+	return cfqq;
+}
+
+static int
+__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+			int max_dispatch)
+{
+	int dispatched = 0;
+
+	BUG_ON(RB_EMPTY(&cfqq->sort_list));
+
+	do {
+		struct cfq_rq *crq;
+
+		/*
+		 * follow expired path, else get first next available
+		 */
+		if ((crq = cfq_check_fifo(cfqq)) == NULL)
+			crq = cfqq->next_crq;
+
+		/*
+		 * finally, insert request into driver dispatch list
+		 */
+		cfq_dispatch_sort(cfqd->queue, crq);
+
+		cfqd->dispatch_slice++;
+		dispatched++;
+
+		if (!cfqd->active_cic) {
+			atomic_inc(&crq->io_context->ioc->refcount);
+			cfqd->active_cic = crq->io_context;
+		}
+
+		if (RB_EMPTY(&cfqq->sort_list))
+			break;
+
+	} while (dispatched < max_dispatch);
+
+	/*
+	 * if slice end isn't set yet, set it. if at least one request was
+	 * sync, use the sync time slice value
+	 */
+	if (!cfqq->slice_end)
+		cfq_set_prio_slice(cfqd, cfqq);
+
+	/*
+	 * expire an async queue immediately if it has used up its slice. idle
+	 * queue always expire after 1 dispatch round.
+	 */
+	if ((!cfq_cfqq_sync(cfqq) &&
+	    cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
+	    cfq_class_idle(cfqq))
+		cfq_slice_expired(cfqd, 0);
+
+	return dispatched;
+}
+
+static int
+cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
 	struct cfq_queue *cfqq;
-	struct list_head *entry, *tmp;
-	int queued, busy_queues, first_round;
 
-	if (list_empty(&cfqd->rr_list))
+	if (!cfqd->busy_queues)
 		return 0;
 
-	queued = 0;
-	first_round = 1;
-restart:
-	busy_queues = 0;
-	list_for_each_safe(entry, tmp, &cfqd->rr_list) {
-		cfqq = list_entry_cfqq(entry);
+	cfqq = cfq_select_queue(cfqd, force);
+	if (cfqq) {
+		cfq_clear_cfqq_must_dispatch(cfqq);
+		cfq_clear_cfqq_wait_request(cfqq);
+		del_timer(&cfqd->idle_slice_timer);
 
-		BUG_ON(RB_EMPTY(&cfqq->sort_list));
+		if (cfq_class_idle(cfqq))
+			max_dispatch = 1;
 
-		/*
-		 * first round of queueing, only select from queues that
-		 * don't already have io in-flight
-		 */
-		if (first_round && cfqq->in_flight)
-			continue;
-
-		cfq_dispatch_request(q, cfqd, cfqq);
-
-		if (!RB_EMPTY(&cfqq->sort_list))
-			busy_queues++;
-
-		queued++;
+		return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
 	}
 
-	if ((queued < max_dispatch) && (busy_queues || first_round)) {
-		first_round = 0;
-		goto restart;
-	}
-
-	return queued;
+	return 0;
 }
 
 static inline void cfq_account_dispatch(struct cfq_rq *crq)
 {
 	struct cfq_queue *cfqq = crq->cfq_queue;
 	struct cfq_data *cfqd = cfqq->cfqd;
-	unsigned long now, elapsed;
 
-	if (!blk_fs_request(crq->request))
+	if (unlikely(!blk_fs_request(crq->request)))
 		return;
 
 	/*
 	 * accounted bit is necessary since some drivers will call
 	 * elv_next_request() many times for the same request (eg ide)
 	 */
-	if (crq->accounted)
+	if (cfq_crq_in_driver(crq))
 		return;
 
-	now = jiffies;
-	if (cfqq->service_start == ~0UL)
-		cfqq->service_start = now;
-
-	/*
-	 * on drives with tagged command queueing, command turn-around time
-	 * doesn't necessarily reflect the time spent processing this very
-	 * command inside the drive. so do the accounting differently there,
-	 * by just sorting on the number of requests
-	 */
-	if (cfqd->cfq_tagged) {
-		if (time_after(now, cfqq->service_start + cfq_service)) {
-			cfqq->service_start = now;
-			cfqq->service_used /= 10;
-		}
-
-		cfqq->service_used++;
-		cfq_sort_rr_list(cfqq, 0);
-	}
-
-	elapsed = now - crq->queue_start;
-	if (elapsed > max_elapsed_dispatch)
-		max_elapsed_dispatch = elapsed;
-
-	crq->accounted = 1;
-	crq->service_start = now;
-
-	if (++cfqd->rq_in_driver >= CFQ_MAX_TAG && !cfqd->cfq_tagged) {
-		cfqq->cfqd->cfq_tagged = 1;
-		printk("cfq: depth %d reached, tagging now on\n", CFQ_MAX_TAG);
-	}
+	cfq_mark_crq_in_driver(crq);
+	cfqd->rq_in_driver++;
 }
 
 static inline void
 cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq)
 {
 	struct cfq_data *cfqd = cfqq->cfqd;
+	unsigned long now;
 
-	if (!crq->accounted)
+	if (!cfq_crq_in_driver(crq))
 		return;
 
+	now = jiffies;
+
 	WARN_ON(!cfqd->rq_in_driver);
 	cfqd->rq_in_driver--;
 
-	if (!cfqd->cfq_tagged) {
-		unsigned long now = jiffies;
-		unsigned long duration = now - crq->service_start;
+	if (!cfq_class_idle(cfqq))
+		cfqd->last_end_request = now;
 
-		if (time_after(now, cfqq->service_start + cfq_service)) {
-			cfqq->service_start = now;
-			cfqq->service_used >>= 3;
+	if (!cfq_cfqq_dispatched(cfqq)) {
+		if (cfq_cfqq_on_rr(cfqq)) {
+			cfqq->service_last = now;
+			cfq_resort_rr_list(cfqq, 0);
 		}
-
-		cfqq->service_used += duration;
-		cfq_sort_rr_list(cfqq, 0);
-
-		if (duration > max_elapsed_crq)
-			max_elapsed_crq = duration;
+		if (cfq_cfqq_expired(cfqq)) {
+			__cfq_slice_expired(cfqd, cfqq, 0);
+			cfq_schedule_dispatch(cfqd);
+		}
 	}
+
+	if (cfq_crq_is_sync(crq))
+		crq->io_context->last_end_request = now;
 }
 
 static struct request *cfq_next_request(request_queue_t *q)
@@ -950,7 +1261,18 @@
 dispatch:
 		rq = list_entry_rq(q->queue_head.next);
 
-		if ((crq = RQ_DATA(rq)) != NULL) {
+		crq = RQ_DATA(rq);
+		if (crq) {
+			struct cfq_queue *cfqq = crq->cfq_queue;
+
+			/*
+			 * if idle window is disabled, allow queue buildup
+			 */
+			if (!cfq_crq_in_driver(crq) &&
+			    !cfq_cfqq_idle_window(cfqq) &&
+			    cfqd->rq_in_driver >= cfqd->cfq_max_depth)
+				return NULL;
+
 			cfq_remove_merge_hints(q, crq);
 			cfq_account_dispatch(crq);
 		}
@@ -958,7 +1280,7 @@
 		return rq;
 	}
 
-	if (cfq_dispatch_requests(q, cfqd->cfq_quantum))
+	if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0))
 		goto dispatch;
 
 	return NULL;
@@ -972,13 +1294,21 @@
  */
 static void cfq_put_queue(struct cfq_queue *cfqq)
 {
-	BUG_ON(!atomic_read(&cfqq->ref));
+	struct cfq_data *cfqd = cfqq->cfqd;
+
+	BUG_ON(atomic_read(&cfqq->ref) <= 0);
 
 	if (!atomic_dec_and_test(&cfqq->ref))
 		return;
 
 	BUG_ON(rb_first(&cfqq->sort_list));
-	BUG_ON(cfqq->on_rr);
+	BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
+	BUG_ON(cfq_cfqq_on_rr(cfqq));
+
+	if (unlikely(cfqd->active_queue == cfqq)) {
+		__cfq_slice_expired(cfqd, cfqq, 0);
+		cfq_schedule_dispatch(cfqd);
+	}
 
 	cfq_put_cfqd(cfqq->cfqd);
 
@@ -991,15 +1321,17 @@
 }
 
 static inline struct cfq_queue *
-__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key, const int hashval)
+__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
+		    const int hashval)
 {
 	struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
 	struct hlist_node *entry, *next;
 
 	hlist_for_each_safe(entry, next, hash_list) {
 		struct cfq_queue *__cfqq = list_entry_qhash(entry);
+		const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->ioprio_class, __cfqq->ioprio);
 
-		if (__cfqq->key == key)
+		if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY))
 			return __cfqq;
 	}
 
@@ -1007,210 +1339,187 @@
 }
 
 static struct cfq_queue *
-cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key)
+cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
 {
-	return __cfq_find_cfq_hash(cfqd, key, hash_long(key, CFQ_QHASH_SHIFT));
-}
-
-static inline void
-cfq_rehash_cfqq(struct cfq_data *cfqd, struct cfq_queue **cfqq,
-		struct cfq_io_context *cic)
-{
-	unsigned long hashkey = cfq_hash_key(cfqd, current);
-	unsigned long hashval = hash_long(hashkey, CFQ_QHASH_SHIFT);
-	struct cfq_queue *__cfqq;
-	unsigned long flags;
-
-	spin_lock_irqsave(cfqd->queue->queue_lock, flags);
-
-	hlist_del(&(*cfqq)->cfq_hash);
-
-	__cfqq = __cfq_find_cfq_hash(cfqd, hashkey, hashval);
-	if (!__cfqq || __cfqq == *cfqq) {
-		__cfqq = *cfqq;
-		hlist_add_head(&__cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
-		__cfqq->key_type = cfqd->key_type;
-	} else {
-		atomic_inc(&__cfqq->ref);
-		cic->cfqq = __cfqq;
-		cfq_put_queue(*cfqq);
-		*cfqq = __cfqq;
-	}
-
-	cic->cfqq = __cfqq;
-	spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+	return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
 }
 
 static void cfq_free_io_context(struct cfq_io_context *cic)
 {
+	struct cfq_io_context *__cic;
+	struct list_head *entry, *next;
+
+	list_for_each_safe(entry, next, &cic->list) {
+		__cic = list_entry(entry, struct cfq_io_context, list);
+		kmem_cache_free(cfq_ioc_pool, __cic);
+	}
+
 	kmem_cache_free(cfq_ioc_pool, cic);
 }
 
 /*
- * locking hierarchy is: io_context lock -> queue locks
+ * Called with interrupts disabled
+ */
+static void cfq_exit_single_io_context(struct cfq_io_context *cic)
+{
+	struct cfq_data *cfqd = cic->cfqq->cfqd;
+	request_queue_t *q = cfqd->queue;
+
+	WARN_ON(!irqs_disabled());
+
+	spin_lock(q->queue_lock);
+
+	if (unlikely(cic->cfqq == cfqd->active_queue)) {
+		__cfq_slice_expired(cfqd, cic->cfqq, 0);
+		cfq_schedule_dispatch(cfqd);
+	}
+
+	cfq_put_queue(cic->cfqq);
+	cic->cfqq = NULL;
+	spin_unlock(q->queue_lock);
+}
+
+/*
+ * Another task may update the task cic list, if it is doing a queue lookup
+ * on its behalf. cfq_cic_lock excludes such concurrent updates
  */
 static void cfq_exit_io_context(struct cfq_io_context *cic)
 {
-	struct cfq_queue *cfqq = cic->cfqq;
-	struct list_head *entry = &cic->list;
-	request_queue_t *q;
+	struct cfq_io_context *__cic;
+	struct list_head *entry;
 	unsigned long flags;
 
+	local_irq_save(flags);
+
 	/*
 	 * put the reference this task is holding to the various queues
 	 */
-	spin_lock_irqsave(&cic->ioc->lock, flags);
-	while ((entry = cic->list.next) != &cic->list) {
-		struct cfq_io_context *__cic;
-
+	list_for_each(entry, &cic->list) {
 		__cic = list_entry(entry, struct cfq_io_context, list);
-		list_del(entry);
-
-		q = __cic->cfqq->cfqd->queue;
-		spin_lock(q->queue_lock);
-		cfq_put_queue(__cic->cfqq);
-		spin_unlock(q->queue_lock);
+		cfq_exit_single_io_context(__cic);
 	}
 
-	q = cfqq->cfqd->queue;
-	spin_lock(q->queue_lock);
-	cfq_put_queue(cfqq);
-	spin_unlock(q->queue_lock);
-
-	cic->cfqq = NULL;
-	spin_unlock_irqrestore(&cic->ioc->lock, flags);
+	cfq_exit_single_io_context(cic);
+	local_irq_restore(flags);
 }
 
-static struct cfq_io_context *cfq_alloc_io_context(int gfp_flags)
+static struct cfq_io_context *
+cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask)
 {
-	struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_flags);
+	struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
 
 	if (cic) {
-		cic->dtor = cfq_free_io_context;
-		cic->exit = cfq_exit_io_context;
 		INIT_LIST_HEAD(&cic->list);
 		cic->cfqq = NULL;
+		cic->key = NULL;
+		cic->last_end_request = jiffies;
+		cic->ttime_total = 0;
+		cic->ttime_samples = 0;
+		cic->ttime_mean = 0;
+		cic->dtor = cfq_free_io_context;
+		cic->exit = cfq_exit_io_context;
 	}
 
 	return cic;
 }
 
+static void cfq_init_prio_data(struct cfq_queue *cfqq)
+{
+	struct task_struct *tsk = current;
+	int ioprio_class;
+
+	if (!cfq_cfqq_prio_changed(cfqq))
+		return;
+
+	ioprio_class = IOPRIO_PRIO_CLASS(tsk->ioprio);
+	switch (ioprio_class) {
+		default:
+			printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
+		case IOPRIO_CLASS_NONE:
+			/*
+			 * no prio set, place us in the middle of the BE classes
+			 */
+			cfqq->ioprio = task_nice_ioprio(tsk);
+			cfqq->ioprio_class = IOPRIO_CLASS_BE;
+			break;
+		case IOPRIO_CLASS_RT:
+			cfqq->ioprio = task_ioprio(tsk);
+			cfqq->ioprio_class = IOPRIO_CLASS_RT;
+			break;
+		case IOPRIO_CLASS_BE:
+			cfqq->ioprio = task_ioprio(tsk);
+			cfqq->ioprio_class = IOPRIO_CLASS_BE;
+			break;
+		case IOPRIO_CLASS_IDLE:
+			cfqq->ioprio_class = IOPRIO_CLASS_IDLE;
+			cfqq->ioprio = 7;
+			cfq_clear_cfqq_idle_window(cfqq);
+			break;
+	}
+
+	/*
+	 * keep track of original prio settings in case we have to temporarily
+	 * elevate the priority of this queue
+	 */
+	cfqq->org_ioprio = cfqq->ioprio;
+	cfqq->org_ioprio_class = cfqq->ioprio_class;
+
+	if (cfq_cfqq_on_rr(cfqq))
+		cfq_resort_rr_list(cfqq, 0);
+
+	cfq_clear_cfqq_prio_changed(cfqq);
+}
+
+static inline void changed_ioprio(struct cfq_queue *cfqq)
+{
+	if (cfqq) {
+		struct cfq_data *cfqd = cfqq->cfqd;
+
+		spin_lock(cfqd->queue->queue_lock);
+		cfq_mark_cfqq_prio_changed(cfqq);
+		cfq_init_prio_data(cfqq);
+		spin_unlock(cfqd->queue->queue_lock);
+	}
+}
+
 /*
- * Setup general io context and cfq io context. There can be several cfq
- * io contexts per general io context, if this process is doing io to more
- * than one device managed by cfq. Note that caller is holding a reference to
- * cfqq, so we don't need to worry about it disappearing
+ * callback from sys_ioprio_set, irqs are disabled
  */
-static struct cfq_io_context *
-cfq_get_io_context(struct cfq_queue **cfqq, int gfp_flags)
+static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
 {
-	struct cfq_data *cfqd = (*cfqq)->cfqd;
-	struct cfq_queue *__cfqq = *cfqq;
-	struct cfq_io_context *cic;
-	struct io_context *ioc;
+	struct cfq_io_context *cic = ioc->cic;
 
-	might_sleep_if(gfp_flags & __GFP_WAIT);
+	changed_ioprio(cic->cfqq);
 
-	ioc = get_io_context(gfp_flags);
-	if (!ioc)
-		return NULL;
+	list_for_each_entry(cic, &cic->list, list)
+		changed_ioprio(cic->cfqq);
 
-	if ((cic = ioc->cic) == NULL) {
-		cic = cfq_alloc_io_context(gfp_flags);
-
-		if (cic == NULL)
-			goto err;
-
-		ioc->cic = cic;
-		cic->ioc = ioc;
-		cic->cfqq = __cfqq;
-		atomic_inc(&__cfqq->ref);
-	} else {
-		struct cfq_io_context *__cic;
-		unsigned long flags;
-
-		/*
-		 * since the first cic on the list is actually the head
-		 * itself, need to check this here or we'll duplicate an
-		 * cic per ioc for no reason
-		 */
-		if (cic->cfqq == __cfqq)
-			goto out;
-
-		/*
-		 * cic exists, check if we already are there. linear search
-		 * should be ok here, the list will usually not be more than
-		 * 1 or a few entries long
-		 */
-		spin_lock_irqsave(&ioc->lock, flags);
-		list_for_each_entry(__cic, &cic->list, list) {
-			/*
-			 * this process is already holding a reference to
-			 * this queue, so no need to get one more
-			 */
-			if (__cic->cfqq == __cfqq) {
-				cic = __cic;
-				spin_unlock_irqrestore(&ioc->lock, flags);
-				goto out;
-			}
-		}
-		spin_unlock_irqrestore(&ioc->lock, flags);
-
-		/*
-		 * nope, process doesn't have a cic assoicated with this
-		 * cfqq yet. get a new one and add to list
-		 */
-		__cic = cfq_alloc_io_context(gfp_flags);
-		if (__cic == NULL)
-			goto err;
-
-		__cic->ioc = ioc;
-		__cic->cfqq = __cfqq;
-		atomic_inc(&__cfqq->ref);
-		spin_lock_irqsave(&ioc->lock, flags);
-		list_add(&__cic->list, &cic->list);
-		spin_unlock_irqrestore(&ioc->lock, flags);
-
-		cic = __cic;
-		*cfqq = __cfqq;
-	}
-
-out:
-	/*
-	 * if key_type has been changed on the fly, we lazily rehash
-	 * each queue at lookup time
-	 */
-	if ((*cfqq)->key_type != cfqd->key_type)
-		cfq_rehash_cfqq(cfqd, cfqq, cic);
-
-	return cic;
-err:
-	put_io_context(ioc);
-	return NULL;
+	return 0;
 }
 
 static struct cfq_queue *
-__cfq_get_queue(struct cfq_data *cfqd, unsigned long key, int gfp_mask)
+cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio,
+	      int gfp_mask)
 {
 	const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
 	struct cfq_queue *cfqq, *new_cfqq = NULL;
 
 retry:
-	cfqq = __cfq_find_cfq_hash(cfqd, key, hashval);
+	cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
 
 	if (!cfqq) {
 		if (new_cfqq) {
 			cfqq = new_cfqq;
 			new_cfqq = NULL;
-		} else {
+		} else if (gfp_mask & __GFP_WAIT) {
 			spin_unlock_irq(cfqd->queue->queue_lock);
 			new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
 			spin_lock_irq(cfqd->queue->queue_lock);
-
-			if (!new_cfqq && !(gfp_mask & __GFP_WAIT))
-				goto out;
-
 			goto retry;
+		} else {
+			cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+			if (!cfqq)
+				goto out;
 		}
 
 		memset(cfqq, 0, sizeof(*cfqq));
@@ -1218,16 +1527,21 @@
 		INIT_HLIST_NODE(&cfqq->cfq_hash);
 		INIT_LIST_HEAD(&cfqq->cfq_list);
 		RB_CLEAR_ROOT(&cfqq->sort_list);
-		INIT_LIST_HEAD(&cfqq->fifo[0]);
-		INIT_LIST_HEAD(&cfqq->fifo[1]);
+		INIT_LIST_HEAD(&cfqq->fifo);
 
 		cfqq->key = key;
 		hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
 		atomic_set(&cfqq->ref, 0);
 		cfqq->cfqd = cfqd;
 		atomic_inc(&cfqd->ref);
-		cfqq->key_type = cfqd->key_type;
-		cfqq->service_start = ~0UL;
+		cfqq->service_last = 0;
+		/*
+		 * set ->slice_left to allow preemption for a new process
+		 */
+		cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
+		cfq_mark_cfqq_idle_window(cfqq);
+		cfq_mark_cfqq_prio_changed(cfqq);
+		cfq_init_prio_data(cfqq);
 	}
 
 	if (new_cfqq)
@@ -1239,55 +1553,309 @@
 	return cfqq;
 }
 
-static void cfq_enqueue(struct cfq_data *cfqd, struct cfq_rq *crq)
+/*
+ * Setup general io context and cfq io context. There can be several cfq
+ * io contexts per general io context, if this process is doing io to more
+ * than one device managed by cfq. Note that caller is holding a reference to
+ * cfqq, so we don't need to worry about it disappearing
+ */
+static struct cfq_io_context *
+cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask)
 {
-	crq->is_sync = 0;
-	if (rq_data_dir(crq->request) == READ || current->flags & PF_SYNCWRITE)
-		crq->is_sync = 1;
+	struct io_context *ioc = NULL;
+	struct cfq_io_context *cic;
+
+	might_sleep_if(gfp_mask & __GFP_WAIT);
+
+	ioc = get_io_context(gfp_mask);
+	if (!ioc)
+		return NULL;
+
+	if ((cic = ioc->cic) == NULL) {
+		cic = cfq_alloc_io_context(cfqd, gfp_mask);
+
+		if (cic == NULL)
+			goto err;
+
+		/*
+		 * manually increment generic io_context usage count, it
+		 * cannot go away since we are already holding one ref to it
+		 */
+		ioc->cic = cic;
+		ioc->set_ioprio = cfq_ioc_set_ioprio;
+		cic->ioc = ioc;
+		cic->key = cfqd;
+		atomic_inc(&cfqd->ref);
+	} else {
+		struct cfq_io_context *__cic;
+
+		/*
+		 * the first cic on the list is actually the head itself
+		 */
+		if (cic->key == cfqd)
+			goto out;
+
+		/*
+		 * cic exists, check if we already are there. linear search
+		 * should be ok here, the list will usually not be more than
+		 * 1 or a few entries long
+		 */
+		list_for_each_entry(__cic, &cic->list, list) {
+			/*
+			 * this process is already holding a reference to
+			 * this queue, so no need to get one more
+			 */
+			if (__cic->key == cfqd) {
+				cic = __cic;
+				goto out;
+			}
+		}
+
+		/*
+		 * nope, process doesn't have a cic assoicated with this
+		 * cfqq yet. get a new one and add to list
+		 */
+		__cic = cfq_alloc_io_context(cfqd, gfp_mask);
+		if (__cic == NULL)
+			goto err;
+
+		__cic->ioc = ioc;
+		__cic->key = cfqd;
+		atomic_inc(&cfqd->ref);
+		list_add(&__cic->list, &cic->list);
+		cic = __cic;
+	}
+
+out:
+	return cic;
+err:
+	put_io_context(ioc);
+	return NULL;
+}
+
+static void
+cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
+{
+	unsigned long elapsed, ttime;
+
+	/*
+	 * if this context already has stuff queued, thinktime is from
+	 * last queue not last end
+	 */
+#if 0
+	if (time_after(cic->last_end_request, cic->last_queue))
+		elapsed = jiffies - cic->last_end_request;
+	else
+		elapsed = jiffies - cic->last_queue;
+#else
+		elapsed = jiffies - cic->last_end_request;
+#endif
+
+	ttime = min(elapsed, 2UL * cfqd->cfq_slice_idle);
+
+	cic->ttime_samples = (7*cic->ttime_samples + 256) / 8;
+	cic->ttime_total = (7*cic->ttime_total + 256*ttime) / 8;
+	cic->ttime_mean = (cic->ttime_total + 128) / cic->ttime_samples;
+}
+
+#define sample_valid(samples)	((samples) > 80)
+
+/*
+ * Disable idle window if the process thinks too long or seeks so much that
+ * it doesn't matter
+ */
+static void
+cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+		       struct cfq_io_context *cic)
+{
+	int enable_idle = cfq_cfqq_idle_window(cfqq);
+
+	if (!cic->ioc->task || !cfqd->cfq_slice_idle)
+		enable_idle = 0;
+	else if (sample_valid(cic->ttime_samples)) {
+		if (cic->ttime_mean > cfqd->cfq_slice_idle)
+			enable_idle = 0;
+		else
+			enable_idle = 1;
+	}
+
+	if (enable_idle)
+		cfq_mark_cfqq_idle_window(cfqq);
+	else
+		cfq_clear_cfqq_idle_window(cfqq);
+}
+
+
+/*
+ * Check if new_cfqq should preempt the currently active queue. Return 0 for
+ * no or if we aren't sure, a 1 will cause a preempt.
+ */
+static int
+cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
+		   struct cfq_rq *crq)
+{
+	struct cfq_queue *cfqq = cfqd->active_queue;
+
+	if (cfq_class_idle(new_cfqq))
+		return 0;
+
+	if (!cfqq)
+		return 1;
+
+	if (cfq_class_idle(cfqq))
+		return 1;
+	if (!cfq_cfqq_wait_request(new_cfqq))
+		return 0;
+	/*
+	 * if it doesn't have slice left, forget it
+	 */
+	if (new_cfqq->slice_left < cfqd->cfq_slice_idle)
+		return 0;
+	if (cfq_crq_is_sync(crq) && !cfq_cfqq_sync(cfqq))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * cfqq preempts the active queue. if we allowed preempt with no slice left,
+ * let it have half of its nominal slice.
+ */
+static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	struct cfq_queue *__cfqq, *next;
+
+	list_for_each_entry_safe(__cfqq, next, &cfqd->cur_rr, cfq_list)
+		cfq_resort_rr_list(__cfqq, 1);
+
+	if (!cfqq->slice_left)
+		cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
+
+	cfqq->slice_end = cfqq->slice_left + jiffies;
+	__cfq_slice_expired(cfqd, cfqq, 1);
+	__cfq_set_active_queue(cfqd, cfqq);
+}
+
+/*
+ * should really be a ll_rw_blk.c helper
+ */
+static void cfq_start_queueing(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	request_queue_t *q = cfqd->queue;
+
+	if (!blk_queue_plugged(q))
+		q->request_fn(q);
+	else
+		__generic_unplug_device(q);
+}
+
+/*
+ * Called when a new fs request (crq) is added (to cfqq). Check if there's
+ * something we should do about it
+ */
+static void
+cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+		 struct cfq_rq *crq)
+{
+	const int sync = cfq_crq_is_sync(crq);
+
+	cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq);
+
+	if (sync) {
+		struct cfq_io_context *cic = crq->io_context;
+
+		cfq_update_io_thinktime(cfqd, cic);
+		cfq_update_idle_window(cfqd, cfqq, cic);
+
+		cic->last_queue = jiffies;
+	}
+
+	if (cfqq == cfqd->active_queue) {
+		/*
+		 * if we are waiting for a request for this queue, let it rip
+		 * immediately and flag that we must not expire this queue
+		 * just now
+		 */
+		if (cfq_cfqq_wait_request(cfqq)) {
+			cfq_mark_cfqq_must_dispatch(cfqq);
+			del_timer(&cfqd->idle_slice_timer);
+			cfq_start_queueing(cfqd, cfqq);
+		}
+	} else if (cfq_should_preempt(cfqd, cfqq, crq)) {
+		/*
+		 * not the active queue - expire current slice if it is
+		 * idle and has expired it's mean thinktime or this new queue
+		 * has some old slice time left and is of higher priority
+		 */
+		cfq_preempt_queue(cfqd, cfqq);
+		cfq_mark_cfqq_must_dispatch(cfqq);
+		cfq_start_queueing(cfqd, cfqq);
+	}
+}
+
+static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq)
+{
+	struct cfq_rq *crq = RQ_DATA(rq);
+	struct cfq_queue *cfqq = crq->cfq_queue;
+
+	cfq_init_prio_data(cfqq);
 
 	cfq_add_crq_rb(crq);
-	crq->queue_start = jiffies;
 
-	list_add_tail(&crq->request->queuelist, &crq->cfq_queue->fifo[crq->is_sync]);
+	list_add_tail(&rq->queuelist, &cfqq->fifo);
+
+	if (rq_mergeable(rq)) {
+		cfq_add_crq_hash(cfqd, crq);
+
+		if (!cfqd->queue->last_merge)
+			cfqd->queue->last_merge = rq;
+	}
+
+	cfq_crq_enqueued(cfqd, cfqq, crq);
 }
 
 static void
 cfq_insert_request(request_queue_t *q, struct request *rq, int where)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
-	struct cfq_rq *crq = RQ_DATA(rq);
 
 	switch (where) {
 		case ELEVATOR_INSERT_BACK:
-			while (cfq_dispatch_requests(q, cfqd->cfq_quantum))
+			while (cfq_dispatch_requests(q, INT_MAX, 1))
 				;
 			list_add_tail(&rq->queuelist, &q->queue_head);
+			/*
+			 * If we were idling with pending requests on
+			 * inactive cfqqs, force dispatching will
+			 * remove the idle timer and the queue won't
+			 * be kicked by __make_request() afterward.
+			 * Kick it here.
+			 */
+			cfq_schedule_dispatch(cfqd);
 			break;
 		case ELEVATOR_INSERT_FRONT:
 			list_add(&rq->queuelist, &q->queue_head);
 			break;
 		case ELEVATOR_INSERT_SORT:
 			BUG_ON(!blk_fs_request(rq));
-			cfq_enqueue(cfqd, crq);
+			cfq_enqueue(cfqd, rq);
 			break;
 		default:
 			printk("%s: bad insert point %d\n", __FUNCTION__,where);
 			return;
 	}
+}
 
-	if (rq_mergeable(rq)) {
-		cfq_add_crq_hash(cfqd, crq);
-
-		if (!q->last_merge)
-			q->last_merge = rq;
-	}
+static inline int cfq_pending_requests(struct cfq_data *cfqd)
+{
+	return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues;
 }
 
 static int cfq_queue_empty(request_queue_t *q)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
 
-	return list_empty(&q->queue_head) && list_empty(&cfqd->rr_list);
+	return !cfq_pending_requests(cfqd);
 }
 
 static void cfq_completed_request(request_queue_t *q, struct request *rq)
@@ -1300,9 +1868,11 @@
 
 	cfqq = crq->cfq_queue;
 
-	if (crq->in_flight) {
-		WARN_ON(!cfqq->in_flight);
-		cfqq->in_flight--;
+	if (cfq_crq_in_flight(crq)) {
+		const int sync = cfq_crq_is_sync(crq);
+
+		WARN_ON(!cfqq->on_dispatch[sync]);
+		cfqq->on_dispatch[sync]--;
 	}
 
 	cfq_account_completion(cfqq, crq);
@@ -1332,51 +1902,136 @@
 	return NULL;
 }
 
-static int cfq_may_queue(request_queue_t *q, int rw)
+/*
+ * we temporarily boost lower priority queues if they are holding fs exclusive
+ * resources. they are boosted to normal prio (CLASS_BE/4)
+ */
+static void cfq_prio_boost(struct cfq_queue *cfqq)
 {
-	struct cfq_data *cfqd = q->elevator->elevator_data;
-	struct cfq_queue *cfqq;
-	int ret = ELV_MQUEUE_MAY;
+	const int ioprio_class = cfqq->ioprio_class;
+	const int ioprio = cfqq->ioprio;
 
-	if (current->flags & PF_MEMALLOC)
-		return ELV_MQUEUE_MAY;
-
-	cfqq = cfq_find_cfq_hash(cfqd, cfq_hash_key(cfqd, current));
-	if (cfqq) {
-		int limit = cfqd->max_queued;
-
-		if (cfqq->allocated[rw] < cfqd->cfq_queued)
-			return ELV_MQUEUE_MUST;
-
-		if (cfqd->busy_queues)
-			limit = q->nr_requests / cfqd->busy_queues;
-
-		if (limit < cfqd->cfq_queued)
-			limit = cfqd->cfq_queued;
-		else if (limit > cfqd->max_queued)
-			limit = cfqd->max_queued;
-
-		if (cfqq->allocated[rw] >= limit) {
-			if (limit > cfqq->alloc_limit[rw])
-				cfqq->alloc_limit[rw] = limit;
-
-			ret = ELV_MQUEUE_NO;
-		}
+	if (has_fs_excl()) {
+		/*
+		 * boost idle prio on transactions that would lock out other
+		 * users of the filesystem
+		 */
+		if (cfq_class_idle(cfqq))
+			cfqq->ioprio_class = IOPRIO_CLASS_BE;
+		if (cfqq->ioprio > IOPRIO_NORM)
+			cfqq->ioprio = IOPRIO_NORM;
+	} else {
+		/*
+		 * check if we need to unboost the queue
+		 */
+		if (cfqq->ioprio_class != cfqq->org_ioprio_class)
+			cfqq->ioprio_class = cfqq->org_ioprio_class;
+		if (cfqq->ioprio != cfqq->org_ioprio)
+			cfqq->ioprio = cfqq->org_ioprio;
 	}
 
-	return ret;
+	/*
+	 * refile between round-robin lists if we moved the priority class
+	 */
+	if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio) &&
+	    cfq_cfqq_on_rr(cfqq))
+		cfq_resort_rr_list(cfqq, 0);
+}
+
+static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
+{
+	if (rw == READ || process_sync(task))
+		return task->pid;
+
+	return CFQ_KEY_ASYNC;
+}
+
+static inline int
+__cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+		struct task_struct *task, int rw)
+{
+#if 1
+	if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
+	    !cfq_cfqq_must_alloc_slice) {
+		cfq_mark_cfqq_must_alloc_slice(cfqq);
+		return ELV_MQUEUE_MUST;
+	}
+
+	return ELV_MQUEUE_MAY;
+#else
+	if (!cfqq || task->flags & PF_MEMALLOC)
+		return ELV_MQUEUE_MAY;
+	if (!cfqq->allocated[rw] || cfq_cfqq_must_alloc(cfqq)) {
+		if (cfq_cfqq_wait_request(cfqq))
+			return ELV_MQUEUE_MUST;
+
+		/*
+		 * only allow 1 ELV_MQUEUE_MUST per slice, otherwise we
+		 * can quickly flood the queue with writes from a single task
+		 */
+		if (rw == READ || !cfq_cfqq_must_alloc_slice) {
+			cfq_mark_cfqq_must_alloc_slice(cfqq);
+			return ELV_MQUEUE_MUST;
+		}
+
+		return ELV_MQUEUE_MAY;
+	}
+	if (cfq_class_idle(cfqq))
+		return ELV_MQUEUE_NO;
+	if (cfqq->allocated[rw] >= cfqd->max_queued) {
+		struct io_context *ioc = get_io_context(GFP_ATOMIC);
+		int ret = ELV_MQUEUE_NO;
+
+		if (ioc && ioc->nr_batch_requests)
+			ret = ELV_MQUEUE_MAY;
+
+		put_io_context(ioc);
+		return ret;
+	}
+
+	return ELV_MQUEUE_MAY;
+#endif
+}
+
+static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
+{
+	struct cfq_data *cfqd = q->elevator->elevator_data;
+	struct task_struct *tsk = current;
+	struct cfq_queue *cfqq;
+
+	/*
+	 * don't force setup of a queue from here, as a call to may_queue
+	 * does not necessarily imply that a request actually will be queued.
+	 * so just lookup a possibly existing queue, or return 'may queue'
+	 * if that fails
+	 */
+	cfqq = cfq_find_cfq_hash(cfqd, cfq_queue_pid(tsk, rw), tsk->ioprio);
+	if (cfqq) {
+		cfq_init_prio_data(cfqq);
+		cfq_prio_boost(cfqq);
+
+		return __cfq_may_queue(cfqd, cfqq, tsk, rw);
+	}
+
+	return ELV_MQUEUE_MAY;
 }
 
 static void cfq_check_waiters(request_queue_t *q, struct cfq_queue *cfqq)
 {
+	struct cfq_data *cfqd = q->elevator->elevator_data;
 	struct request_list *rl = &q->rq;
-	const int write = waitqueue_active(&rl->wait[WRITE]);
-	const int read = waitqueue_active(&rl->wait[READ]);
 
-	if (read && cfqq->allocated[READ] < cfqq->alloc_limit[READ])
-		wake_up(&rl->wait[READ]);
-	if (write && cfqq->allocated[WRITE] < cfqq->alloc_limit[WRITE])
-		wake_up(&rl->wait[WRITE]);
+	if (cfqq->allocated[READ] <= cfqd->max_queued || cfqd->rq_starved) {
+		smp_mb();
+		if (waitqueue_active(&rl->wait[READ]))
+			wake_up(&rl->wait[READ]);
+	}
+
+	if (cfqq->allocated[WRITE] <= cfqd->max_queued || cfqd->rq_starved) {
+		smp_mb();
+		if (waitqueue_active(&rl->wait[WRITE]))
+			wake_up(&rl->wait[WRITE]);
+	}
 }
 
 /*
@@ -1389,69 +2044,61 @@
 
 	if (crq) {
 		struct cfq_queue *cfqq = crq->cfq_queue;
+		const int rw = rq_data_dir(rq);
 
-		BUG_ON(q->last_merge == rq);
-		BUG_ON(!hlist_unhashed(&crq->hash));
+		BUG_ON(!cfqq->allocated[rw]);
+		cfqq->allocated[rw]--;
 
-		if (crq->io_context)
-			put_io_context(crq->io_context->ioc);
-
-		BUG_ON(!cfqq->allocated[crq->is_write]);
-		cfqq->allocated[crq->is_write]--;
+		put_io_context(crq->io_context->ioc);
 
 		mempool_free(crq, cfqd->crq_pool);
 		rq->elevator_private = NULL;
 
-		smp_mb();
 		cfq_check_waiters(q, cfqq);
 		cfq_put_queue(cfqq);
 	}
 }
 
 /*
- * Allocate cfq data structures associated with this request. A queue and
+ * Allocate cfq data structures associated with this request.
  */
-static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+static int
+cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+		int gfp_mask)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
+	struct task_struct *tsk = current;
 	struct cfq_io_context *cic;
 	const int rw = rq_data_dir(rq);
-	struct cfq_queue *cfqq, *saved_cfqq;
+	pid_t key = cfq_queue_pid(tsk, rw);
+	struct cfq_queue *cfqq;
 	struct cfq_rq *crq;
 	unsigned long flags;
 
 	might_sleep_if(gfp_mask & __GFP_WAIT);
 
+	cic = cfq_get_io_context(cfqd, key, gfp_mask);
+
 	spin_lock_irqsave(q->queue_lock, flags);
 
-	cfqq = __cfq_get_queue(cfqd, cfq_hash_key(cfqd, current), gfp_mask);
-	if (!cfqq)
-		goto out_lock;
+	if (!cic)
+		goto queue_fail;
 
-repeat:
-	if (cfqq->allocated[rw] >= cfqd->max_queued)
-		goto out_lock;
+	if (!cic->cfqq) {
+		cfqq = cfq_get_queue(cfqd, key, tsk->ioprio, gfp_mask);
+		if (!cfqq)
+			goto queue_fail;
+
+		cic->cfqq = cfqq;
+	} else
+		cfqq = cic->cfqq;
 
 	cfqq->allocated[rw]++;
+	cfq_clear_cfqq_must_alloc(cfqq);
+	cfqd->rq_starved = 0;
+	atomic_inc(&cfqq->ref);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 
-	/*
-	 * if hashing type has changed, the cfq_queue might change here.
-	 */
-	saved_cfqq = cfqq;
-	cic = cfq_get_io_context(&cfqq, gfp_mask);
-	if (!cic)
-		goto err;
-
-	/*
-	 * repeat allocation checks on queue change
-	 */
-	if (unlikely(saved_cfqq != cfqq)) {
-		spin_lock_irqsave(q->queue_lock, flags);
-		saved_cfqq->allocated[rw]--;
-		goto repeat;
-	}
-
 	crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
 	if (crq) {
 		RB_CLEAR(&crq->rb_node);
@@ -1460,24 +2107,141 @@
 		INIT_HLIST_NODE(&crq->hash);
 		crq->cfq_queue = cfqq;
 		crq->io_context = cic;
-		crq->service_start = crq->queue_start = 0;
-		crq->in_flight = crq->accounted = crq->is_sync = 0;
-		crq->is_write = rw;
+		cfq_clear_crq_in_flight(crq);
+		cfq_clear_crq_in_driver(crq);
+		cfq_clear_crq_requeued(crq);
+
+		if (rw == READ || process_sync(tsk))
+			cfq_mark_crq_is_sync(crq);
+		else
+			cfq_clear_crq_is_sync(crq);
+
 		rq->elevator_private = crq;
-		cfqq->alloc_limit[rw] = 0;
 		return 0;
 	}
 
-	put_io_context(cic->ioc);
-err:
 	spin_lock_irqsave(q->queue_lock, flags);
 	cfqq->allocated[rw]--;
+	if (!(cfqq->allocated[0] + cfqq->allocated[1]))
+		cfq_mark_cfqq_must_alloc(cfqq);
 	cfq_put_queue(cfqq);
-out_lock:
+queue_fail:
+	if (cic)
+		put_io_context(cic->ioc);
+	/*
+	 * mark us rq allocation starved. we need to kickstart the process
+	 * ourselves if there are no pending requests that can do it for us.
+	 * that would be an extremely rare OOM situation
+	 */
+	cfqd->rq_starved = 1;
+	cfq_schedule_dispatch(cfqd);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 	return 1;
 }
 
+static void cfq_kick_queue(void *data)
+{
+	request_queue_t *q = data;
+	struct cfq_data *cfqd = q->elevator->elevator_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	if (cfqd->rq_starved) {
+		struct request_list *rl = &q->rq;
+
+		/*
+		 * we aren't guaranteed to get a request after this, but we
+		 * have to be opportunistic
+		 */
+		smp_mb();
+		if (waitqueue_active(&rl->wait[READ]))
+			wake_up(&rl->wait[READ]);
+		if (waitqueue_active(&rl->wait[WRITE]))
+			wake_up(&rl->wait[WRITE]);
+	}
+
+	blk_remove_plug(q);
+	q->request_fn(q);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+/*
+ * Timer running if the active_queue is currently idling inside its time slice
+ */
+static void cfq_idle_slice_timer(unsigned long data)
+{
+	struct cfq_data *cfqd = (struct cfq_data *) data;
+	struct cfq_queue *cfqq;
+	unsigned long flags;
+
+	spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+	if ((cfqq = cfqd->active_queue) != NULL) {
+		unsigned long now = jiffies;
+
+		/*
+		 * expired
+		 */
+		if (time_after(now, cfqq->slice_end))
+			goto expire;
+
+		/*
+		 * only expire and reinvoke request handler, if there are
+		 * other queues with pending requests
+		 */
+		if (!cfq_pending_requests(cfqd)) {
+			cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end);
+			add_timer(&cfqd->idle_slice_timer);
+			goto out_cont;
+		}
+
+		/*
+		 * not expired and it has a request pending, let it dispatch
+		 */
+		if (!RB_EMPTY(&cfqq->sort_list)) {
+			cfq_mark_cfqq_must_dispatch(cfqq);
+			goto out_kick;
+		}
+	}
+expire:
+	cfq_slice_expired(cfqd, 0);
+out_kick:
+	cfq_schedule_dispatch(cfqd);
+out_cont:
+	spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+/*
+ * Timer running if an idle class queue is waiting for service
+ */
+static void cfq_idle_class_timer(unsigned long data)
+{
+	struct cfq_data *cfqd = (struct cfq_data *) data;
+	unsigned long flags, end;
+
+	spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+	/*
+	 * race with a non-idle queue, reset timer
+	 */
+	end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+	if (!time_after_eq(jiffies, end)) {
+		cfqd->idle_class_timer.expires = end;
+		add_timer(&cfqd->idle_class_timer);
+	} else
+		cfq_schedule_dispatch(cfqd);
+
+	spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
+{
+	del_timer_sync(&cfqd->idle_slice_timer);
+	del_timer_sync(&cfqd->idle_class_timer);
+	blk_sync_queue(cfqd->queue);
+}
+
 static void cfq_put_cfqd(struct cfq_data *cfqd)
 {
 	request_queue_t *q = cfqd->queue;
@@ -1487,6 +2251,9 @@
 
 	blk_put_queue(q);
 
+	cfq_shutdown_timer_wq(cfqd);
+	q->elevator->elevator_data = NULL;
+
 	mempool_destroy(cfqd->crq_pool);
 	kfree(cfqd->crq_hash);
 	kfree(cfqd->cfq_hash);
@@ -1495,7 +2262,10 @@
 
 static void cfq_exit_queue(elevator_t *e)
 {
-	cfq_put_cfqd(e->elevator_data);
+	struct cfq_data *cfqd = e->elevator_data;
+
+	cfq_shutdown_timer_wq(cfqd);
+	cfq_put_cfqd(cfqd);
 }
 
 static int cfq_init_queue(request_queue_t *q, elevator_t *e)
@@ -1508,7 +2278,13 @@
 		return -ENOMEM;
 
 	memset(cfqd, 0, sizeof(*cfqd));
-	INIT_LIST_HEAD(&cfqd->rr_list);
+
+	for (i = 0; i < CFQ_PRIO_LISTS; i++)
+		INIT_LIST_HEAD(&cfqd->rr_list[i]);
+
+	INIT_LIST_HEAD(&cfqd->busy_rr);
+	INIT_LIST_HEAD(&cfqd->cur_rr);
+	INIT_LIST_HEAD(&cfqd->idle_rr);
 	INIT_LIST_HEAD(&cfqd->empty_list);
 
 	cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
@@ -1533,24 +2309,32 @@
 	cfqd->queue = q;
 	atomic_inc(&q->refcnt);
 
-	/*
-	 * just set it to some high value, we want anyone to be able to queue
-	 * some requests. fairness is handled differently
-	 */
-	q->nr_requests = 1024;
-	cfqd->max_queued = q->nr_requests / 16;
+	cfqd->max_queued = q->nr_requests / 4;
 	q->nr_batching = cfq_queued;
-	cfqd->key_type = CFQ_KEY_TGID;
-	cfqd->find_best_crq = 1;
+
+	init_timer(&cfqd->idle_slice_timer);
+	cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
+	cfqd->idle_slice_timer.data = (unsigned long) cfqd;
+
+	init_timer(&cfqd->idle_class_timer);
+	cfqd->idle_class_timer.function = cfq_idle_class_timer;
+	cfqd->idle_class_timer.data = (unsigned long) cfqd;
+
+	INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q);
+
 	atomic_set(&cfqd->ref, 1);
 
 	cfqd->cfq_queued = cfq_queued;
 	cfqd->cfq_quantum = cfq_quantum;
-	cfqd->cfq_fifo_expire_r = cfq_fifo_expire_r;
-	cfqd->cfq_fifo_expire_w = cfq_fifo_expire_w;
-	cfqd->cfq_fifo_batch_expire = cfq_fifo_rate;
+	cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
+	cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1];
 	cfqd->cfq_back_max = cfq_back_max;
 	cfqd->cfq_back_penalty = cfq_back_penalty;
+	cfqd->cfq_slice[0] = cfq_slice_async;
+	cfqd->cfq_slice[1] = cfq_slice_sync;
+	cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
+	cfqd->cfq_slice_idle = cfq_slice_idle;
+	cfqd->cfq_max_depth = cfq_max_depth;
 
 	return 0;
 out_crqpool:
@@ -1595,7 +2379,6 @@
 	return -ENOMEM;
 }
 
-
 /*
  * sysfs parts below -->
  */
@@ -1620,45 +2403,6 @@
 	return count;
 }
 
-static ssize_t
-cfq_clear_elapsed(struct cfq_data *cfqd, const char *page, size_t count)
-{
-	max_elapsed_dispatch = max_elapsed_crq = 0;
-	return count;
-}
-
-static ssize_t
-cfq_set_key_type(struct cfq_data *cfqd, const char *page, size_t count)
-{
-	spin_lock_irq(cfqd->queue->queue_lock);
-	if (!strncmp(page, "pgid", 4))
-		cfqd->key_type = CFQ_KEY_PGID;
-	else if (!strncmp(page, "tgid", 4))
-		cfqd->key_type = CFQ_KEY_TGID;
-	else if (!strncmp(page, "uid", 3))
-		cfqd->key_type = CFQ_KEY_UID;
-	else if (!strncmp(page, "gid", 3))
-		cfqd->key_type = CFQ_KEY_GID;
-	spin_unlock_irq(cfqd->queue->queue_lock);
-	return count;
-}
-
-static ssize_t
-cfq_read_key_type(struct cfq_data *cfqd, char *page)
-{
-	ssize_t len = 0;
-	int i;
-
-	for (i = CFQ_KEY_PGID; i < CFQ_KEY_LAST; i++) {
-		if (cfqd->key_type == i)
-			len += sprintf(page+len, "[%s] ", cfq_key_types[i]);
-		else
-			len += sprintf(page+len, "%s ", cfq_key_types[i]);
-	}
-	len += sprintf(page+len, "\n");
-	return len;
-}
-
 #define SHOW_FUNCTION(__FUNC, __VAR, __CONV)				\
 static ssize_t __FUNC(struct cfq_data *cfqd, char *page)		\
 {									\
@@ -1669,12 +2413,15 @@
 }
 SHOW_FUNCTION(cfq_quantum_show, cfqd->cfq_quantum, 0);
 SHOW_FUNCTION(cfq_queued_show, cfqd->cfq_queued, 0);
-SHOW_FUNCTION(cfq_fifo_expire_r_show, cfqd->cfq_fifo_expire_r, 1);
-SHOW_FUNCTION(cfq_fifo_expire_w_show, cfqd->cfq_fifo_expire_w, 1);
-SHOW_FUNCTION(cfq_fifo_batch_expire_show, cfqd->cfq_fifo_batch_expire, 1);
-SHOW_FUNCTION(cfq_find_best_show, cfqd->find_best_crq, 0);
+SHOW_FUNCTION(cfq_fifo_expire_sync_show, cfqd->cfq_fifo_expire[1], 1);
+SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1);
 SHOW_FUNCTION(cfq_back_max_show, cfqd->cfq_back_max, 0);
 SHOW_FUNCTION(cfq_back_penalty_show, cfqd->cfq_back_penalty, 0);
+SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1);
+SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
+SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
+SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
+SHOW_FUNCTION(cfq_max_depth_show, cfqd->cfq_max_depth, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)			\
@@ -1694,12 +2441,15 @@
 }
 STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0);
 STORE_FUNCTION(cfq_queued_store, &cfqd->cfq_queued, 1, UINT_MAX, 0);
-STORE_FUNCTION(cfq_fifo_expire_r_store, &cfqd->cfq_fifo_expire_r, 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_expire_w_store, &cfqd->cfq_fifo_expire_w, 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_batch_expire_store, &cfqd->cfq_fifo_batch_expire, 0, UINT_MAX, 1);
-STORE_FUNCTION(cfq_find_best_store, &cfqd->find_best_crq, 0, 1, 0);
+STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_back_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
 STORE_FUNCTION(cfq_back_penalty_store, &cfqd->cfq_back_penalty, 1, UINT_MAX, 0);
+STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX, 0);
+STORE_FUNCTION(cfq_max_depth_store, &cfqd->cfq_max_depth, 1, UINT_MAX, 0);
 #undef STORE_FUNCTION
 
 static struct cfq_fs_entry cfq_quantum_entry = {
@@ -1712,25 +2462,15 @@
 	.show = cfq_queued_show,
 	.store = cfq_queued_store,
 };
-static struct cfq_fs_entry cfq_fifo_expire_r_entry = {
+static struct cfq_fs_entry cfq_fifo_expire_sync_entry = {
 	.attr = {.name = "fifo_expire_sync", .mode = S_IRUGO | S_IWUSR },
-	.show = cfq_fifo_expire_r_show,
-	.store = cfq_fifo_expire_r_store,
+	.show = cfq_fifo_expire_sync_show,
+	.store = cfq_fifo_expire_sync_store,
 };
-static struct cfq_fs_entry cfq_fifo_expire_w_entry = {
+static struct cfq_fs_entry cfq_fifo_expire_async_entry = {
 	.attr = {.name = "fifo_expire_async", .mode = S_IRUGO | S_IWUSR },
-	.show = cfq_fifo_expire_w_show,
-	.store = cfq_fifo_expire_w_store,
-};
-static struct cfq_fs_entry cfq_fifo_batch_expire_entry = {
-	.attr = {.name = "fifo_batch_expire", .mode = S_IRUGO | S_IWUSR },
-	.show = cfq_fifo_batch_expire_show,
-	.store = cfq_fifo_batch_expire_store,
-};
-static struct cfq_fs_entry cfq_find_best_entry = {
-	.attr = {.name = "find_best_crq", .mode = S_IRUGO | S_IWUSR },
-	.show = cfq_find_best_show,
-	.store = cfq_find_best_store,
+	.show = cfq_fifo_expire_async_show,
+	.store = cfq_fifo_expire_async_store,
 };
 static struct cfq_fs_entry cfq_back_max_entry = {
 	.attr = {.name = "back_seek_max", .mode = S_IRUGO | S_IWUSR },
@@ -1742,27 +2482,44 @@
 	.show = cfq_back_penalty_show,
 	.store = cfq_back_penalty_store,
 };
-static struct cfq_fs_entry cfq_clear_elapsed_entry = {
-	.attr = {.name = "clear_elapsed", .mode = S_IWUSR },
-	.store = cfq_clear_elapsed,
+static struct cfq_fs_entry cfq_slice_sync_entry = {
+	.attr = {.name = "slice_sync", .mode = S_IRUGO | S_IWUSR },
+	.show = cfq_slice_sync_show,
+	.store = cfq_slice_sync_store,
 };
-static struct cfq_fs_entry cfq_key_type_entry = {
-	.attr = {.name = "key_type", .mode = S_IRUGO | S_IWUSR },
-	.show = cfq_read_key_type,
-	.store = cfq_set_key_type,
+static struct cfq_fs_entry cfq_slice_async_entry = {
+	.attr = {.name = "slice_async", .mode = S_IRUGO | S_IWUSR },
+	.show = cfq_slice_async_show,
+	.store = cfq_slice_async_store,
+};
+static struct cfq_fs_entry cfq_slice_async_rq_entry = {
+	.attr = {.name = "slice_async_rq", .mode = S_IRUGO | S_IWUSR },
+	.show = cfq_slice_async_rq_show,
+	.store = cfq_slice_async_rq_store,
+};
+static struct cfq_fs_entry cfq_slice_idle_entry = {
+	.attr = {.name = "slice_idle", .mode = S_IRUGO | S_IWUSR },
+	.show = cfq_slice_idle_show,
+	.store = cfq_slice_idle_store,
+};
+static struct cfq_fs_entry cfq_max_depth_entry = {
+	.attr = {.name = "max_depth", .mode = S_IRUGO | S_IWUSR },
+	.show = cfq_max_depth_show,
+	.store = cfq_max_depth_store,
 };
 
 static struct attribute *default_attrs[] = {
 	&cfq_quantum_entry.attr,
 	&cfq_queued_entry.attr,
-	&cfq_fifo_expire_r_entry.attr,
-	&cfq_fifo_expire_w_entry.attr,
-	&cfq_fifo_batch_expire_entry.attr,
-	&cfq_key_type_entry.attr,
-	&cfq_find_best_entry.attr,
+	&cfq_fifo_expire_sync_entry.attr,
+	&cfq_fifo_expire_async_entry.attr,
 	&cfq_back_max_entry.attr,
 	&cfq_back_penalty_entry.attr,
-	&cfq_clear_elapsed_entry.attr,
+	&cfq_slice_sync_entry.attr,
+	&cfq_slice_async_entry.attr,
+	&cfq_slice_async_rq_entry.attr,
+	&cfq_slice_idle_entry.attr,
+	&cfq_max_depth_entry.attr,
 	NULL,
 };
 
@@ -1832,21 +2589,46 @@
 {
 	int ret;
 
+	/*
+	 * could be 0 on HZ < 1000 setups
+	 */
+	if (!cfq_slice_async)
+		cfq_slice_async = 1;
+	if (!cfq_slice_idle)
+		cfq_slice_idle = 1;
+
 	if (cfq_slab_setup())
 		return -ENOMEM;
 
 	ret = elv_register(&iosched_cfq);
-	if (!ret) {
-		__module_get(THIS_MODULE);
-		return 0;
-	}
+	if (ret)
+		cfq_slab_kill();
 
-	cfq_slab_kill();
 	return ret;
 }
 
 static void __exit cfq_exit(void)
 {
+	struct task_struct *g, *p;
+	unsigned long flags;
+
+	read_lock_irqsave(&tasklist_lock, flags);
+
+	/*
+	 * iterate each process in the system, removing our io_context
+	 */
+	do_each_thread(g, p) {
+		struct io_context *ioc = p->io_context;
+
+		if (ioc && ioc->cic) {
+			ioc->cic->exit(ioc->cic);
+			cfq_free_io_context(ioc->cic);
+			ioc->cic = NULL;
+		}
+	} while_each_thread(g, p);
+
+	read_unlock_irqrestore(&tasklist_lock, flags);
+
 	cfq_slab_kill();
 	elv_unregister(&iosched_cfq);
 }
diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
index 4bc2fea..ff5201e 100644
--- a/drivers/block/deadline-iosched.c
+++ b/drivers/block/deadline-iosched.c
@@ -760,7 +760,8 @@
 }
 
 static int
-deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+		     int gfp_mask)
 {
 	struct deadline_data *dd = q->elevator->elevator_data;
 	struct deadline_rq *drq;
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index f831f08..98f0126 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -486,12 +486,13 @@
 	return NULL;
 }
 
-int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+		    int gfp_mask)
 {
 	elevator_t *e = q->elevator;
 
 	if (e->ops->elevator_set_req_fn)
-		return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
+		return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
 
 	rq->elevator_private = NULL;
 	return 0;
@@ -505,12 +506,12 @@
 		e->ops->elevator_put_req_fn(q, rq);
 }
 
-int elv_may_queue(request_queue_t *q, int rw)
+int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
 {
 	elevator_t *e = q->elevator;
 
 	if (e->ops->elevator_may_queue_fn)
-		return e->ops->elevator_may_queue_fn(q, rw);
+		return e->ops->elevator_may_queue_fn(q, rw, bio);
 
 	return ELV_MQUEUE_MAY;
 }
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 60e6409..234fdcf 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -276,6 +276,7 @@
 	rq->errors = 0;
 	rq->rq_status = RQ_ACTIVE;
 	rq->bio = rq->biotail = NULL;
+	rq->ioprio = 0;
 	rq->buffer = NULL;
 	rq->ref_count = 1;
 	rq->q = q;
@@ -1442,11 +1443,7 @@
 	if (!blk_remove_plug(q))
 		return;
 
-	/*
-	 * was plugged, fire request_fn if queue has stuff to do
-	 */
-	if (elv_next_request(q))
-		q->request_fn(q);
+	q->request_fn(q);
 }
 EXPORT_SYMBOL(__generic_unplug_device);
 
@@ -1776,8 +1773,8 @@
 	mempool_free(rq, q->rq.rq_pool);
 }
 
-static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
-						int gfp_mask)
+static inline struct request *
+blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask)
 {
 	struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
 
@@ -1790,7 +1787,7 @@
 	 */
 	rq->flags = rw;
 
-	if (!elv_set_request(q, rq, gfp_mask))
+	if (!elv_set_request(q, rq, bio, gfp_mask))
 		return rq;
 
 	mempool_free(rq, q->rq.rq_pool);
@@ -1872,7 +1869,8 @@
 /*
  * Get a free request, queue_lock must not be held
  */
-static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
+static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
+				   int gfp_mask)
 {
 	struct request *rq = NULL;
 	struct request_list *rl = &q->rq;
@@ -1895,7 +1893,7 @@
 		}
 	}
 
-	switch (elv_may_queue(q, rw)) {
+	switch (elv_may_queue(q, rw, bio)) {
 		case ELV_MQUEUE_NO:
 			goto rq_starved;
 		case ELV_MQUEUE_MAY:
@@ -1920,7 +1918,7 @@
 		set_queue_congested(q, rw);
 	spin_unlock_irq(q->queue_lock);
 
-	rq = blk_alloc_request(q, rw, gfp_mask);
+	rq = blk_alloc_request(q, rw, bio, gfp_mask);
 	if (!rq) {
 		/*
 		 * Allocation failed presumably due to memory. Undo anything
@@ -1961,7 +1959,8 @@
  * No available requests for this queue, unplug the device and wait for some
  * requests to become available.
  */
-static struct request *get_request_wait(request_queue_t *q, int rw)
+static struct request *get_request_wait(request_queue_t *q, int rw,
+					struct bio *bio)
 {
 	DEFINE_WAIT(wait);
 	struct request *rq;
@@ -1972,7 +1971,7 @@
 		prepare_to_wait_exclusive(&rl->wait[rw], &wait,
 				TASK_UNINTERRUPTIBLE);
 
-		rq = get_request(q, rw, GFP_NOIO);
+		rq = get_request(q, rw, bio, GFP_NOIO);
 
 		if (!rq) {
 			struct io_context *ioc;
@@ -2003,9 +2002,9 @@
 	BUG_ON(rw != READ && rw != WRITE);
 
 	if (gfp_mask & __GFP_WAIT)
-		rq = get_request_wait(q, rw);
+		rq = get_request_wait(q, rw, NULL);
 	else
-		rq = get_request(q, rw, gfp_mask);
+		rq = get_request(q, rw, NULL, gfp_mask);
 
 	return rq;
 }
@@ -2333,7 +2332,6 @@
 		return;
 
 	req->rq_status = RQ_INACTIVE;
-	req->q = NULL;
 	req->rl = NULL;
 
 	/*
@@ -2462,6 +2460,8 @@
 		req->rq_disk->in_flight--;
 	}
 
+	req->ioprio = ioprio_best(req->ioprio, next->ioprio);
+
 	__blk_put_request(q, next);
 	return 1;
 }
@@ -2514,11 +2514,13 @@
 {
 	struct request *req, *freereq = NULL;
 	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
+	unsigned short prio;
 	sector_t sector;
 
 	sector = bio->bi_sector;
 	nr_sectors = bio_sectors(bio);
 	cur_nr_sectors = bio_cur_sectors(bio);
+	prio = bio_prio(bio);
 
 	rw = bio_data_dir(bio);
 	sync = bio_sync(bio);
@@ -2559,6 +2561,7 @@
 			req->biotail->bi_next = bio;
 			req->biotail = bio;
 			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+			req->ioprio = ioprio_best(req->ioprio, prio);
 			drive_stat_acct(req, nr_sectors, 0);
 			if (!attempt_back_merge(q, req))
 				elv_merged_request(q, req);
@@ -2583,6 +2586,7 @@
 			req->hard_cur_sectors = cur_nr_sectors;
 			req->sector = req->hard_sector = sector;
 			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+			req->ioprio = ioprio_best(req->ioprio, prio);
 			drive_stat_acct(req, nr_sectors, 0);
 			if (!attempt_front_merge(q, req))
 				elv_merged_request(q, req);
@@ -2610,7 +2614,7 @@
 		freereq = NULL;
 	} else {
 		spin_unlock_irq(q->queue_lock);
-		if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) {
+		if ((freereq = get_request(q, rw, bio, GFP_ATOMIC)) == NULL) {
 			/*
 			 * READA bit set
 			 */
@@ -2618,7 +2622,7 @@
 			if (bio_rw_ahead(bio))
 				goto end_io;
 	
-			freereq = get_request_wait(q, rw);
+			freereq = get_request_wait(q, rw, bio);
 		}
 		goto again;
 	}
@@ -2646,6 +2650,7 @@
 	req->buffer = bio_data(bio);	/* see ->buffer comment above */
 	req->waiting = NULL;
 	req->bio = req->biotail = bio;
+	req->ioprio = prio;
 	req->rq_disk = bio->bi_bdev->bd_disk;
 	req->start_time = jiffies;
 
@@ -2674,7 +2679,7 @@
 	if (bdev != bdev->bd_contains) {
 		struct hd_struct *p = bdev->bd_part;
 
-		switch (bio->bi_rw) {
+		switch (bio_data_dir(bio)) {
 		case READ:
 			p->read_sectors += bio_sectors(bio);
 			p->reads++;
@@ -2693,6 +2698,7 @@
 {
 	struct request_list *rl = &q->rq;
 	struct request *rq;
+	int requeued = 0;
 
 	spin_lock_irq(q->queue_lock);
 	clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
@@ -2701,9 +2707,13 @@
 		rq = list_entry_rq(q->drain_list.next);
 
 		list_del_init(&rq->queuelist);
-		__elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
+		elv_requeue_request(q, rq);
+		requeued++;
 	}
 
+	if (requeued)
+		q->request_fn(q);
+
 	spin_unlock_irq(q->queue_lock);
 
 	wake_up(&rl->wait[0]);
@@ -2900,7 +2910,7 @@
 
 	BIO_BUG_ON(!bio->bi_size);
 	BIO_BUG_ON(!bio->bi_io_vec);
-	bio->bi_rw = rw;
+	bio->bi_rw |= rw;
 	if (rw & WRITE)
 		mod_page_state(pgpgout, count);
 	else
@@ -3257,8 +3267,11 @@
 	struct io_context *ioc;
 
 	local_irq_save(flags);
+	task_lock(current);
 	ioc = current->io_context;
 	current->io_context = NULL;
+	ioc->task = NULL;
+	task_unlock(current);
 	local_irq_restore(flags);
 
 	if (ioc->aic && ioc->aic->exit)
@@ -3293,12 +3306,12 @@
 	ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
 	if (ret) {
 		atomic_set(&ret->refcount, 1);
-		ret->pid = tsk->pid;
+		ret->task = current;
+		ret->set_ioprio = NULL;
 		ret->last_waited = jiffies; /* doesn't matter... */
 		ret->nr_batch_requests = 0; /* because this is 0 */
 		ret->aic = NULL;
 		ret->cic = NULL;
-		spin_lock_init(&ret->lock);
 
 		local_irq_save(flags);
 
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 5b09cf1..e5f7494 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -253,7 +253,7 @@
 static int swim3_add_device(struct device_node *swims);
 int swim3_init(void);
 
-#ifndef CONFIG_PMAC_PBOOK
+#ifndef CONFIG_PMAC_MEDIABAY
 #define check_media_bay(which, what)	1
 #endif
 
@@ -297,9 +297,11 @@
 	int i;
 	for(i=0;i<floppy_count;i++)
 	{
+#ifdef CONFIG_PMAC_MEDIABAY
 		if (floppy_states[i].media_bay &&
 			check_media_bay(floppy_states[i].media_bay, MB_FD))
 			continue;
+#endif /* CONFIG_PMAC_MEDIABAY */
 		start_request(&floppy_states[i]);
 	}
 	sti();
@@ -856,8 +858,10 @@
 	if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
+#ifdef CONFIG_PMAC_MEDIABAY
 	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 		return -ENXIO;
+#endif
 
 	switch (cmd) {
 	case FDEJECT:
@@ -881,8 +885,10 @@
 	int n, err = 0;
 
 	if (fs->ref_count == 0) {
+#ifdef CONFIG_PMAC_MEDIABAY
 		if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 			return -ENXIO;
+#endif
 		out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
 		out_8(&sw->control_bic, 0xff);
 		out_8(&sw->mode, 0x95);
@@ -967,8 +973,10 @@
 	struct swim3 __iomem *sw;
 	int ret, n;
 
+#ifdef CONFIG_PMAC_MEDIABAY
 	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 		return -ENXIO;
+#endif
 
 	sw = fs->swim3;
 	grab_drive(fs, revalidating, 0);
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 5ed3a63..9db0a9e 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/hdreg.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -1582,9 +1583,9 @@
 		goto err_out;
 
 #if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
-	rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+	rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
 	if (!rc) {
-		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 		if (rc) {
 			printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
 				pci_name(pdev));
@@ -1593,7 +1594,7 @@
 		pci_dac = 1;
 	} else {
 #endif
-		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc) {
 			printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
 				pci_name(pdev));
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 31cf84d..931efd5 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -309,9 +309,6 @@
 #ifdef CONFIG_BVME6000
 	rtc_DP8570A_init();
 #endif
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_device_init();
-#endif
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 		printk("unable to get major %d for misc devices\n",
 		       MISC_MAJOR);
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 569f167..818380b 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1324,9 +1324,9 @@
 	/* XXX FIXME: Media bay stuff need re-organizing */
 	if (np->parent && np->parent->name
 	    && strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PMAC_MEDIABAY
 		media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PMAC_MEDIABAY */
 		pmif->mediabay = 1;
 		if (!bidp)
 			pmif->aapl_bus_id = 1;
@@ -1382,10 +1382,10 @@
 	       hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
 	       pmif->mediabay ? " (mediabay)" : "", hwif->irq);
 			
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PMAC_MEDIABAY
 	if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
 		hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PMAC_MEDIABAY */
 
 	hwif->sg_max_nents = MAX_DCMDS;
 
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 36e25ac..b3d3d22 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -3538,8 +3538,8 @@
 
 static int ohci1394_pci_resume (struct pci_dev *pdev)
 {
-#ifdef CONFIG_PMAC_PBOOK
-	{
+#ifdef CONFIG_PPC_PMAC
+	if (_machine == _MACH_Pmac) {
 		struct device_node *of_node;
 
 		/* Re-enable 1394 */
@@ -3547,7 +3547,7 @@
 		if (of_node)
 			pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1);
 	}
-#endif
+#endif /* CONFIG_PPC_PMAC */
 
 	pci_enable_device(pdev);
 
@@ -3557,8 +3557,8 @@
 
 static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 {
-#ifdef CONFIG_PMAC_PBOOK
-	{
+#ifdef CONFIG_PPC_PMAC
+	if (_machine == _MACH_Pmac) {
 		struct device_node *of_node;
 
 		/* Disable 1394 */
diff --git a/drivers/infiniband/core/packer.c b/drivers/infiniband/core/packer.c
index 5f15fef..eb5ff54 100644
--- a/drivers/infiniband/core/packer.c
+++ b/drivers/infiniband/core/packer.c
@@ -96,7 +96,7 @@
 			else
 				val = 0;
 
-			mask = cpu_to_be64(((1ull << desc[i].size_bits) - 1) << shift);
+			mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift);
 			addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words);
 			*addr = (*addr & ~mask) | (cpu_to_be64(val) & mask);
 		} else {
@@ -176,7 +176,7 @@
 			__be64 *addr;
 
 			shift = 64 - desc[i].offset_bits - desc[i].size_bits;
-			mask = ((1ull << desc[i].size_bits) - 1) << shift;
+			mask = (~0ull >> (64 - desc[i].size_bits)) << shift;
 			addr = (__be64 *) buf + desc[i].offset_words;
 			val = (be64_to_cpup(addr) & mask) >> shift;
 			value_write(desc[i].struct_offset_bytes,
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 276e1a5..5a08e81 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -507,7 +507,13 @@
 		spin_unlock_irqrestore(&idr_lock, flags);
 	}
 
-	return ret;
+	/*
+	 * It's not safe to dereference query any more, because the
+	 * send may already have completed and freed the query in
+	 * another context.  So use wr.wr_id, which has a copy of the
+	 * query's id.
+	 */
+	return ret ? ret : wr.wr_id;
 }
 
 static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
@@ -598,14 +604,15 @@
 		rec, query->sa_query.mad->data);
 
 	*sa_query = &query->sa_query;
+
 	ret = send_mad(&query->sa_query, timeout_ms);
-	if (ret) {
+	if (ret < 0) {
 		*sa_query = NULL;
 		kfree(query->sa_query.mad);
 		kfree(query);
 	}
 
-	return ret ? ret : query->sa_query.id;
+	return ret;
 }
 EXPORT_SYMBOL(ib_sa_path_rec_get);
 
@@ -674,14 +681,15 @@
 		rec, query->sa_query.mad->data);
 
 	*sa_query = &query->sa_query;
+
 	ret = send_mad(&query->sa_query, timeout_ms);
-	if (ret) {
+	if (ret < 0) {
 		*sa_query = NULL;
 		kfree(query->sa_query.mad);
 		kfree(query);
 	}
 
-	return ret ? ret : query->sa_query.id;
+	return ret;
 }
 EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
 
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index 085baf3..d58dcbe 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index cd9ed95..1557a52 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -431,6 +431,36 @@
 				      timeout, status);
 }
 
+int mthca_cmd_init(struct mthca_dev *dev)
+{
+	sema_init(&dev->cmd.hcr_sem, 1);
+	sema_init(&dev->cmd.poll_sem, 1);
+	dev->cmd.use_events = 0;
+
+	dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
+			   MTHCA_HCR_SIZE);
+	if (!dev->hcr) {
+		mthca_err(dev, "Couldn't map command register.");
+		return -ENOMEM;
+	}
+
+	dev->cmd.pool = pci_pool_create("mthca_cmd", dev->pdev,
+					MTHCA_MAILBOX_SIZE,
+					MTHCA_MAILBOX_SIZE, 0);
+	if (!dev->cmd.pool) {
+		iounmap(dev->hcr);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void mthca_cmd_cleanup(struct mthca_dev *dev)
+{
+	pci_pool_destroy(dev->cmd.pool);
+	iounmap(dev->hcr);
+}
+
 /*
  * Switch to using events to issue FW commands (should be called after
  * event queue to command events has been initialized).
@@ -489,6 +519,33 @@
 	up(&dev->cmd.poll_sem);
 }
 
+struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
+					  unsigned int gfp_mask)
+{
+	struct mthca_mailbox *mailbox;
+
+	mailbox = kmalloc(sizeof *mailbox, gfp_mask);
+	if (!mailbox)
+		return ERR_PTR(-ENOMEM);
+
+	mailbox->buf = pci_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma);
+	if (!mailbox->buf) {
+		kfree(mailbox);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return mailbox;
+}
+
+void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox)
+{
+	if (!mailbox)
+		return;
+
+	pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
+	kfree(mailbox);
+}
+
 int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
 {
 	u64 out;
@@ -513,20 +570,20 @@
 static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 			 u64 virt, u8 *status)
 {
-	u32 *inbox;
-	dma_addr_t indma;
+	struct mthca_mailbox *mailbox;
 	struct mthca_icm_iter iter;
+	__be64 *pages;
 	int lg;
 	int nent = 0;
 	int i;
 	int err = 0;
 	int ts = 0, tc = 0;
 
-	inbox = pci_alloc_consistent(dev->pdev, PAGE_SIZE, &indma);
-	if (!inbox)
-		return -ENOMEM;
-
-	memset(inbox, 0, PAGE_SIZE);
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	memset(mailbox->buf, 0, MTHCA_MAILBOX_SIZE);
+	pages = mailbox->buf;
 
 	for (mthca_icm_first(icm, &iter);
 	     !mthca_icm_last(&iter);
@@ -546,19 +603,17 @@
 		}
 		for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i, ++nent) {
 			if (virt != -1) {
-				*((__be64 *) (inbox + nent * 4)) =
-					cpu_to_be64(virt);
+				pages[nent * 2] = cpu_to_be64(virt);
 				virt += 1 << lg;
 			}
 
-			*((__be64 *) (inbox + nent * 4 + 2)) =
-				cpu_to_be64((mthca_icm_addr(&iter) +
-					     (i << lg)) | (lg - 12));
+			pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
+							   (i << lg)) | (lg - 12));
 			ts += 1 << (lg - 10);
 			++tc;
 
-			if (nent == PAGE_SIZE / 16) {
-				err = mthca_cmd(dev, indma, nent, 0, op,
+			if (nent == MTHCA_MAILBOX_SIZE / 16) {
+				err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
 						CMD_TIME_CLASS_B, status);
 				if (err || *status)
 					goto out;
@@ -568,7 +623,7 @@
 	}
 
 	if (nent)
-		err = mthca_cmd(dev, indma, nent, 0, op,
+		err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
 				CMD_TIME_CLASS_B, status);
 
 	switch (op) {
@@ -585,7 +640,7 @@
 	}
 
 out:
-	pci_free_consistent(dev->pdev, PAGE_SIZE, inbox, indma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
@@ -606,8 +661,8 @@
 
 int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u32 *outbox;
-	dma_addr_t outdma;
 	int err = 0;
 	u8 lg;
 
@@ -625,12 +680,12 @@
 #define QUERY_FW_EQ_ARM_BASE_OFFSET    0x40
 #define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48
 
-	outbox = pci_alloc_consistent(dev->pdev, QUERY_FW_OUT_SIZE, &outdma);
-	if (!outbox) {
-		return -ENOMEM;
-	}
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	outbox = mailbox->buf;
 
-	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_FW,
+	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW,
 			    CMD_TIME_CLASS_A, status);
 
 	if (err)
@@ -681,15 +736,15 @@
 	}
 
 out:
-	pci_free_consistent(dev->pdev, QUERY_FW_OUT_SIZE, outbox, outdma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
 int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u8 info;
 	u32 *outbox;
-	dma_addr_t outdma;
 	int err = 0;
 
 #define ENABLE_LAM_OUT_SIZE         0x100
@@ -700,11 +755,12 @@
 #define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4)
 #define ENABLE_LAM_INFO_ECC_MASK    0x3
 
-	outbox = pci_alloc_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, &outdma);
-	if (!outbox)
-		return -ENOMEM;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	outbox = mailbox->buf;
 
-	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_ENABLE_LAM,
+	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM,
 			    CMD_TIME_CLASS_C, status);
 
 	if (err)
@@ -733,7 +789,7 @@
 		  (unsigned long long) dev->ddr_end);
 
 out:
-	pci_free_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, outbox, outdma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
@@ -744,9 +800,9 @@
 
 int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u8 info;
 	u32 *outbox;
-	dma_addr_t outdma;
 	int err = 0;
 
 #define QUERY_DDR_OUT_SIZE         0x100
@@ -757,11 +813,12 @@
 #define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4)
 #define QUERY_DDR_INFO_ECC_MASK    0x3
 
-	outbox = pci_alloc_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, &outdma);
-	if (!outbox)
-		return -ENOMEM;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	outbox = mailbox->buf;
 
-	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DDR,
+	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR,
 			    CMD_TIME_CLASS_A, status);
 
 	if (err)
@@ -787,15 +844,15 @@
 		  (unsigned long long) dev->ddr_end);
 
 out:
-	pci_free_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, outbox, outdma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
 int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 			struct mthca_dev_lim *dev_lim, u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u32 *outbox;
-	dma_addr_t outdma;
 	u8 field;
 	u16 size;
 	int err;
@@ -860,11 +917,12 @@
 #define QUERY_DEV_LIM_LAMR_OFFSET           0x9f
 #define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET     0xa0
 
-	outbox = pci_alloc_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, &outdma);
-	if (!outbox)
-		return -ENOMEM;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	outbox = mailbox->buf;
 
-	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DEV_LIM,
+	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM,
 			    CMD_TIME_CLASS_A, status);
 
 	if (err)
@@ -1020,15 +1078,15 @@
 	}
 
 out:
-	pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
 int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 			struct mthca_adapter *adapter, u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u32 *outbox;
-	dma_addr_t outdma;
 	int err;
 
 #define QUERY_ADAPTER_OUT_SIZE             0x100
@@ -1037,23 +1095,24 @@
 #define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
 #define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
 
-	outbox = pci_alloc_consistent(dev->pdev, QUERY_ADAPTER_OUT_SIZE, &outdma);
-	if (!outbox)
-		return -ENOMEM;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	outbox = mailbox->buf;
 
-	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_ADAPTER,
+	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER,
 			    CMD_TIME_CLASS_A, status);
 
 	if (err)
 		goto out;
 
-	MTHCA_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET);
-	MTHCA_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET);
+	MTHCA_GET(adapter->vendor_id, outbox,   QUERY_ADAPTER_VENDOR_ID_OFFSET);
+	MTHCA_GET(adapter->device_id, outbox,   QUERY_ADAPTER_DEVICE_ID_OFFSET);
 	MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
-	MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET);
+	MTHCA_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
 
 out:
-	pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
@@ -1061,8 +1120,8 @@
 		   struct mthca_init_hca_param *param,
 		   u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u32 *inbox;
-	dma_addr_t indma;
 	int err;
 
 #define INIT_HCA_IN_SIZE             	 0x200
@@ -1102,9 +1161,10 @@
 #define  INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10)
 #define  INIT_HCA_UAR_CTX_BASE_OFFSET    (INIT_HCA_UAR_OFFSET + 0x18)
 
-	inbox = pci_alloc_consistent(dev->pdev, INIT_HCA_IN_SIZE, &indma);
-	if (!inbox)
-		return -ENOMEM;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	inbox = mailbox->buf;
 
 	memset(inbox, 0, INIT_HCA_IN_SIZE);
 
@@ -1167,10 +1227,9 @@
 		MTHCA_PUT(inbox, param->uarc_base,   INIT_HCA_UAR_CTX_BASE_OFFSET);
 	}
 
-	err = mthca_cmd(dev, indma, 0, 0, CMD_INIT_HCA,
-			HZ, status);
+	err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, HZ, status);
 
-	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
@@ -1178,8 +1237,8 @@
 		  struct mthca_init_ib_param *param,
 		  int port, u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u32 *inbox;
-	dma_addr_t indma;
 	int err;
 	u32 flags;
 
@@ -1199,9 +1258,10 @@
 #define INIT_IB_NODE_GUID_OFFSET 0x18
 #define INIT_IB_SI_GUID_OFFSET   0x20
 
-	inbox = pci_alloc_consistent(dev->pdev, INIT_IB_IN_SIZE, &indma);
-	if (!inbox)
-		return -ENOMEM;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	inbox = mailbox->buf;
 
 	memset(inbox, 0, INIT_IB_IN_SIZE);
 
@@ -1221,10 +1281,10 @@
 	MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET);
 	MTHCA_PUT(inbox, param->si_guid,   INIT_IB_SI_GUID_OFFSET);
 
-	err = mthca_cmd(dev, indma, port, 0, CMD_INIT_IB,
+	err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB,
 			CMD_TIME_CLASS_A, status);
 
-	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
@@ -1241,8 +1301,8 @@
 int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 		 int port, u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u32 *inbox;
-	dma_addr_t indma;
 	int err;
 	u32 flags = 0;
 
@@ -1253,9 +1313,10 @@
 #define SET_IB_CAP_MASK_OFFSET 0x04
 #define SET_IB_SI_GUID_OFFSET  0x08
 
-	inbox = pci_alloc_consistent(dev->pdev, SET_IB_IN_SIZE, &indma);
-	if (!inbox)
-		return -ENOMEM;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	inbox = mailbox->buf;
 
 	memset(inbox, 0, SET_IB_IN_SIZE);
 
@@ -1266,10 +1327,10 @@
 	MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET);
 	MTHCA_PUT(inbox, param->si_guid,  SET_IB_SI_GUID_OFFSET);
 
-	err = mthca_cmd(dev, indma, port, 0, CMD_SET_IB,
+	err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB,
 			CMD_TIME_CLASS_B, status);
 
-	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
@@ -1280,20 +1341,22 @@
 
 int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status)
 {
+	struct mthca_mailbox *mailbox;
 	u64 *inbox;
-	dma_addr_t indma;
 	int err;
 
-	inbox = pci_alloc_consistent(dev->pdev, 16, &indma);
-	if (!inbox)
-		return -ENOMEM;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	inbox = mailbox->buf;
 
 	inbox[0] = cpu_to_be64(virt);
 	inbox[1] = cpu_to_be64(dma_addr);
 
-	err = mthca_cmd(dev, indma, 1, 0, CMD_MAP_ICM, CMD_TIME_CLASS_B, status);
+	err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM,
+			CMD_TIME_CLASS_B, status);
 
-	pci_free_consistent(dev->pdev, 16, inbox, indma);
+	mthca_free_mailbox(dev, mailbox);
 
 	if (!err)
 		mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
@@ -1338,69 +1401,26 @@
 	return 0;
 }
 
-int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int mpt_index, u8 *status)
 {
-	dma_addr_t indma;
-	int err;
-
-	indma = pci_map_single(dev->pdev, mpt_entry,
-			       MTHCA_MPT_ENTRY_SIZE,
-			       PCI_DMA_TODEVICE);
-	if (pci_dma_mapping_error(indma))
-		return -ENOMEM;
-
-	err = mthca_cmd(dev, indma, mpt_index, 0, CMD_SW2HW_MPT,
-			CMD_TIME_CLASS_B, status);
-
-	pci_unmap_single(dev->pdev, indma,
-			 MTHCA_MPT_ENTRY_SIZE, PCI_DMA_TODEVICE);
-	return err;
+	return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT,
+			 CMD_TIME_CLASS_B, status);
 }
 
-int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int mpt_index, u8 *status)
 {
-	dma_addr_t outdma = 0;
-	int err;
-
-	if (mpt_entry) {
-		outdma = pci_map_single(dev->pdev, mpt_entry,
-					MTHCA_MPT_ENTRY_SIZE,
-					PCI_DMA_FROMDEVICE);
-		if (pci_dma_mapping_error(outdma))
-			return -ENOMEM;
-	}
-
-	err = mthca_cmd_box(dev, 0, outdma, mpt_index, !mpt_entry,
-			    CMD_HW2SW_MPT,
-			    CMD_TIME_CLASS_B, status);
-
-	if (mpt_entry)
-		pci_unmap_single(dev->pdev, outdma,
-				 MTHCA_MPT_ENTRY_SIZE,
-				 PCI_DMA_FROMDEVICE);
-	return err;
+	return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
+			     !mailbox, CMD_HW2SW_MPT,
+			     CMD_TIME_CLASS_B, status);
 }
 
-int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
+int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int num_mtt, u8 *status)
 {
-	dma_addr_t indma;
-	int err;
-
-	indma = pci_map_single(dev->pdev, mtt_entry,
-			       (num_mtt + 2) * 8,
-			       PCI_DMA_TODEVICE);
-	if (pci_dma_mapping_error(indma))
-		return -ENOMEM;
-
-	err = mthca_cmd(dev, indma, num_mtt, 0, CMD_WRITE_MTT,
-			CMD_TIME_CLASS_B, status);
-
-	pci_unmap_single(dev->pdev, indma,
-			 (num_mtt + 2) * 8, PCI_DMA_TODEVICE);
-	return err;
+	return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT,
+			 CMD_TIME_CLASS_B, status);
 }
 
 int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status)
@@ -1418,92 +1438,38 @@
 			 0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status);
 }
 
-int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int eq_num, u8 *status)
 {
-	dma_addr_t indma;
-	int err;
-
-	indma = pci_map_single(dev->pdev, eq_context,
-			       MTHCA_EQ_CONTEXT_SIZE,
-			       PCI_DMA_TODEVICE);
-	if (pci_dma_mapping_error(indma))
-		return -ENOMEM;
-
-	err = mthca_cmd(dev, indma, eq_num, 0, CMD_SW2HW_EQ,
-			CMD_TIME_CLASS_A, status);
-
-	pci_unmap_single(dev->pdev, indma,
-			 MTHCA_EQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
-	return err;
+	return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ,
+			 CMD_TIME_CLASS_A, status);
 }
 
-int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int eq_num, u8 *status)
 {
-	dma_addr_t outdma = 0;
-	int err;
-
-	outdma = pci_map_single(dev->pdev, eq_context,
-				MTHCA_EQ_CONTEXT_SIZE,
-				PCI_DMA_FROMDEVICE);
-	if (pci_dma_mapping_error(outdma))
-		return -ENOMEM;
-
-	err = mthca_cmd_box(dev, 0, outdma, eq_num, 0,
-			    CMD_HW2SW_EQ,
-			    CMD_TIME_CLASS_A, status);
-
-	pci_unmap_single(dev->pdev, outdma,
-			 MTHCA_EQ_CONTEXT_SIZE,
-			 PCI_DMA_FROMDEVICE);
-	return err;
+	return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0,
+			     CMD_HW2SW_EQ,
+			     CMD_TIME_CLASS_A, status);
 }
 
-int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int cq_num, u8 *status)
 {
-	dma_addr_t indma;
-	int err;
-
-	indma = pci_map_single(dev->pdev, cq_context,
-			       MTHCA_CQ_CONTEXT_SIZE,
-			       PCI_DMA_TODEVICE);
-	if (pci_dma_mapping_error(indma))
-		return -ENOMEM;
-
-	err = mthca_cmd(dev, indma, cq_num, 0, CMD_SW2HW_CQ,
+	return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ,
 			CMD_TIME_CLASS_A, status);
-
-	pci_unmap_single(dev->pdev, indma,
-			 MTHCA_CQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
-	return err;
 }
 
-int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int cq_num, u8 *status)
 {
-	dma_addr_t outdma = 0;
-	int err;
-
-	outdma = pci_map_single(dev->pdev, cq_context,
-				MTHCA_CQ_CONTEXT_SIZE,
-				PCI_DMA_FROMDEVICE);
-	if (pci_dma_mapping_error(outdma))
-		return -ENOMEM;
-
-	err = mthca_cmd_box(dev, 0, outdma, cq_num, 0,
-			    CMD_HW2SW_CQ,
-			    CMD_TIME_CLASS_A, status);
-
-	pci_unmap_single(dev->pdev, outdma,
-			 MTHCA_CQ_CONTEXT_SIZE,
-			 PCI_DMA_FROMDEVICE);
-	return err;
+	return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0,
+			     CMD_HW2SW_CQ,
+			     CMD_TIME_CLASS_A, status);
 }
 
 int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-		    int is_ee, void *qp_context, u32 optmask,
+		    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
 		    u8 *status)
 {
 	static const u16 op[] = {
@@ -1520,36 +1486,34 @@
 		[MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
 	};
 	u8 op_mod = 0;
-
-	dma_addr_t indma;
+	int my_mailbox = 0;
 	int err;
 
 	if (trans < 0 || trans >= ARRAY_SIZE(op))
 		return -EINVAL;
 
 	if (trans == MTHCA_TRANS_ANY2RST) {
-		indma  = 0;
 		op_mod = 3;	/* don't write outbox, any->reset */
 
 		/* For debugging */
-		qp_context = pci_alloc_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
-						  &indma);
-		op_mod = 2;	/* write outbox, any->reset */
+		if (!mailbox) {
+			mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+			if (!IS_ERR(mailbox)) {
+				my_mailbox = 1;
+				op_mod     = 2;	/* write outbox, any->reset */
+			} else
+				mailbox = NULL;
+		}
 	} else {
-		indma = pci_map_single(dev->pdev, qp_context,
-				       MTHCA_QP_CONTEXT_SIZE,
-				       PCI_DMA_TODEVICE);
-		if (pci_dma_mapping_error(indma))
-			return -ENOMEM;
-
 		if (0) {
 			int i;
 			mthca_dbg(dev, "Dumping QP context:\n");
-			printk("  opt param mask: %08x\n", be32_to_cpup(qp_context));
+			printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
 			for (i = 0; i < 0x100 / 4; ++i) {
 				if (i % 8 == 0)
 					printk("  [%02x] ", i * 4);
-				printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
+				printk(" %08x",
+				       be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
 				if ((i + 1) % 8 == 0)
 					printk("\n");
 			}
@@ -1557,55 +1521,39 @@
 	}
 
 	if (trans == MTHCA_TRANS_ANY2RST) {
-		err = mthca_cmd_box(dev, 0, indma, (!!is_ee << 24) | num,
-				    op_mod, op[trans], CMD_TIME_CLASS_C, status);
+		err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
+				    (!!is_ee << 24) | num, op_mod,
+				    op[trans], CMD_TIME_CLASS_C, status);
 
-		if (0) {
+		if (0 && mailbox) {
 			int i;
 			mthca_dbg(dev, "Dumping QP context:\n");
-			printk(" %08x\n", be32_to_cpup(qp_context));
+			printk(" %08x\n", be32_to_cpup(mailbox->buf));
 			for (i = 0; i < 0x100 / 4; ++i) {
 				if (i % 8 == 0)
 					printk("[%02x] ", i * 4);
-				printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
+				printk(" %08x",
+				       be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
 				if ((i + 1) % 8 == 0)
 					printk("\n");
 			}
 		}
 
 	} else
-		err = mthca_cmd(dev, indma, (!!is_ee << 24) | num,
+		err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
 				op_mod, op[trans], CMD_TIME_CLASS_C, status);
 
-	if (trans != MTHCA_TRANS_ANY2RST)
-		pci_unmap_single(dev->pdev, indma,
-				 MTHCA_QP_CONTEXT_SIZE, PCI_DMA_TODEVICE);
-	else
-		pci_free_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
-				    qp_context, indma);
+	if (my_mailbox)
+		mthca_free_mailbox(dev, mailbox);
+
 	return err;
 }
 
 int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
-		   void *qp_context, u8 *status)
+		   struct mthca_mailbox *mailbox, u8 *status)
 {
-	dma_addr_t outdma = 0;
-	int err;
-
-	outdma = pci_map_single(dev->pdev, qp_context,
-				MTHCA_QP_CONTEXT_SIZE,
-				PCI_DMA_FROMDEVICE);
-	if (pci_dma_mapping_error(outdma))
-		return -ENOMEM;
-
-	err = mthca_cmd_box(dev, 0, outdma, (!!is_ee << 24) | num, 0,
-			    CMD_QUERY_QPEE,
-			    CMD_TIME_CLASS_A, status);
-
-	pci_unmap_single(dev->pdev, outdma,
-			 MTHCA_QP_CONTEXT_SIZE,
-			 PCI_DMA_FROMDEVICE);
-	return err;
+	return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0,
+			     CMD_QUERY_QPEE, CMD_TIME_CLASS_A, status);
 }
 
 int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
@@ -1635,11 +1583,11 @@
 }
 
 int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
-		  int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
+		  int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
 		  void *in_mad, void *response_mad, u8 *status)
 {
-	void *box;
-	dma_addr_t dma;
+	struct mthca_mailbox *inmailbox, *outmailbox;
+	void *inbox;
 	int err;
 	u32 in_modifier = port;
 	u8 op_modifier = 0;
@@ -1653,11 +1601,18 @@
 #define MAD_IFC_PKEY_OFFSET   0x10e
 #define MAD_IFC_GRH_OFFSET    0x140
 
-	box = pci_alloc_consistent(dev->pdev, MAD_IFC_BOX_SIZE, &dma);
-	if (!box)
-		return -ENOMEM;
+	inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(inmailbox))
+		return PTR_ERR(inmailbox);
+	inbox = inmailbox->buf;
 
-	memcpy(box, in_mad, 256);
+	outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(outmailbox)) {
+		mthca_free_mailbox(dev, inmailbox);
+		return PTR_ERR(outmailbox);
+	}
+
+	memcpy(inbox, in_mad, 256);
 
 	/*
 	 * Key check traps can't be generated unless we have in_wc to
@@ -1671,97 +1626,65 @@
 	if (in_wc) {
 		u8 val;
 
-		memset(box + 256, 0, 256);
+		memset(inbox + 256, 0, 256);
 
-		MTHCA_PUT(box, in_wc->qp_num, 	  MAD_IFC_MY_QPN_OFFSET);
-		MTHCA_PUT(box, in_wc->src_qp, 	  MAD_IFC_RQPN_OFFSET);
+		MTHCA_PUT(inbox, in_wc->qp_num,     MAD_IFC_MY_QPN_OFFSET);
+		MTHCA_PUT(inbox, in_wc->src_qp,     MAD_IFC_RQPN_OFFSET);
 
 		val = in_wc->sl << 4;
-		MTHCA_PUT(box, val,               MAD_IFC_SL_OFFSET);
+		MTHCA_PUT(inbox, val,               MAD_IFC_SL_OFFSET);
 
 		val = in_wc->dlid_path_bits |
 			(in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
-		MTHCA_PUT(box, val,               MAD_IFC_GRH_OFFSET);
+		MTHCA_PUT(inbox, val,               MAD_IFC_GRH_OFFSET);
 
-		MTHCA_PUT(box, in_wc->slid,       MAD_IFC_RLID_OFFSET);
-		MTHCA_PUT(box, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
+		MTHCA_PUT(inbox, in_wc->slid,       MAD_IFC_RLID_OFFSET);
+		MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
 
 		if (in_grh)
-			memcpy((u8 *) box + MAD_IFC_GRH_OFFSET, in_grh, 40);
+			memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40);
 
 		op_modifier |= 0x10;
 
 		in_modifier |= in_wc->slid << 16;
 	}
 
-	err = mthca_cmd_box(dev, dma, dma + 512, in_modifier, op_modifier,
+	err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma,
+			    in_modifier, op_modifier,
 			    CMD_MAD_IFC, CMD_TIME_CLASS_C, status);
 
 	if (!err && !*status)
-		memcpy(response_mad, box + 512, 256);
+		memcpy(response_mad, outmailbox->buf, 256);
 
-	pci_free_consistent(dev->pdev, MAD_IFC_BOX_SIZE, box, dma);
+	mthca_free_mailbox(dev, inmailbox);
+	mthca_free_mailbox(dev, outmailbox);
 	return err;
 }
 
-int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
-		   u8 *status)
+int mthca_READ_MGM(struct mthca_dev *dev, int index,
+		   struct mthca_mailbox *mailbox, u8 *status)
 {
-	dma_addr_t outdma = 0;
-	int err;
-
-	outdma = pci_map_single(dev->pdev, mgm,
-				MTHCA_MGM_ENTRY_SIZE,
-				PCI_DMA_FROMDEVICE);
-	if (pci_dma_mapping_error(outdma))
-		return -ENOMEM;
-
-	err = mthca_cmd_box(dev, 0, outdma, index, 0,
-			    CMD_READ_MGM,
-			    CMD_TIME_CLASS_A, status);
-
-	pci_unmap_single(dev->pdev, outdma,
-			 MTHCA_MGM_ENTRY_SIZE,
-			 PCI_DMA_FROMDEVICE);
-	return err;
+	return mthca_cmd_box(dev, 0, mailbox->dma, index, 0,
+			     CMD_READ_MGM, CMD_TIME_CLASS_A, status);
 }
 
-int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
-		    u8 *status)
+int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
+		    struct mthca_mailbox *mailbox, u8 *status)
 {
-	dma_addr_t indma;
-	int err;
-
-	indma = pci_map_single(dev->pdev, mgm,
-			       MTHCA_MGM_ENTRY_SIZE,
-			       PCI_DMA_TODEVICE);
-	if (pci_dma_mapping_error(indma))
-		return -ENOMEM;
-
-	err = mthca_cmd(dev, indma, index, 0, CMD_WRITE_MGM,
-			CMD_TIME_CLASS_A, status);
-
-	pci_unmap_single(dev->pdev, indma,
-			 MTHCA_MGM_ENTRY_SIZE, PCI_DMA_TODEVICE);
-	return err;
+	return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM,
+			 CMD_TIME_CLASS_A, status);
 }
 
-int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
-		    u8 *status)
+int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+		    u16 *hash, u8 *status)
 {
-	dma_addr_t indma;
 	u64 imm;
 	int err;
 
-	indma = pci_map_single(dev->pdev, gid, 16, PCI_DMA_TODEVICE);
-	if (pci_dma_mapping_error(indma))
-		return -ENOMEM;
-
-	err = mthca_cmd_imm(dev, indma, &imm, 0, 0, CMD_MGID_HASH,
+	err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
 			    CMD_TIME_CLASS_A, status);
-	*hash = imm;
 
-	pci_unmap_single(dev->pdev, indma, 16, PCI_DMA_TODEVICE);
+	*hash = imm;
 	return err;
 }
 
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h
index adf039b..ed517f1 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -37,8 +37,7 @@
 
 #include <ib_verbs.h>
 
-#define MTHCA_CMD_MAILBOX_ALIGN 16UL
-#define MTHCA_CMD_MAILBOX_EXTRA (MTHCA_CMD_MAILBOX_ALIGN - 1)
+#define MTHCA_MAILBOX_SIZE 4096
 
 enum {
 	/* command completed successfully: */
@@ -112,6 +111,11 @@
 	DEV_LIM_FLAG_UD_MULTI           = 1 << 21,
 };
 
+struct mthca_mailbox {
+	dma_addr_t dma;
+	void      *buf;
+};
+
 struct mthca_dev_lim {
 	int max_srq_sz;
 	int max_qp_sz;
@@ -235,11 +239,17 @@
 	u32 cap_mask;
 };
 
+int mthca_cmd_init(struct mthca_dev *dev);
+void mthca_cmd_cleanup(struct mthca_dev *dev);
 int mthca_cmd_use_events(struct mthca_dev *dev);
 void mthca_cmd_use_polling(struct mthca_dev *dev);
 void mthca_cmd_event(struct mthca_dev *dev, u16 token,
 		     u8  status, u64 out_param);
 
+struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
+					  unsigned int gfp_mask);
+void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox);
+
 int mthca_SYS_EN(struct mthca_dev *dev, u8 *status);
 int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status);
 int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
@@ -270,41 +280,39 @@
 int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status);
 int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
 		       u8 *status);
-int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int mpt_index, u8 *status);
-int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int mpt_index, u8 *status);
-int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
+int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int num_mtt, u8 *status);
 int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status);
 int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
 		 int eq_num, u8 *status);
-int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int eq_num, u8 *status);
-int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int eq_num, u8 *status);
-int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int cq_num, u8 *status);
-int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int cq_num, u8 *status);
 int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-		    int is_ee, void *qp_context, u32 optmask,
+		    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
 		    u8 *status);
 int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
-		   void *qp_context, u8 *status);
+		   struct mthca_mailbox *mailbox, u8 *status);
 int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 			  u8 *status);
 int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
-		  int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
+		  int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
 		  void *in_mad, void *response_mad, u8 *status);
-int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
-		   u8 *status);
-int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
-		    u8 *status);
-int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
-		    u8 *status);
+int mthca_READ_MGM(struct mthca_dev *dev, int index,
+		   struct mthca_mailbox *mailbox, u8 *status);
+int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
+		    struct mthca_mailbox *mailbox, u8 *status);
+int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+		    u16 *hash, u8 *status);
 int mthca_NOP(struct mthca_dev *dev, u8 *status);
 
-#define MAILBOX_ALIGN(x) ((void *) ALIGN((unsigned long) (x), MTHCA_CMD_MAILBOX_ALIGN))
-
 #endif /* MTHCA_CMD_H */
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 2bf347b..766e9031 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -171,6 +172,17 @@
 	cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
 }
 
+static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
+{
+	__be32 *cqe = cqe_ptr;
+
+	(void) cqe;	/* avoid warning if mthca_dbg compiled away... */
+	mthca_dbg(dev, "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		  be32_to_cpu(cqe[0]), be32_to_cpu(cqe[1]), be32_to_cpu(cqe[2]),
+		  be32_to_cpu(cqe[3]), be32_to_cpu(cqe[4]), be32_to_cpu(cqe[5]),
+		  be32_to_cpu(cqe[6]), be32_to_cpu(cqe[7]));
+}
+
 /*
  * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
  * should be correct before calling update_cons_index().
@@ -280,16 +292,12 @@
 	int dbd;
 	u32 new_wqe;
 
-	if (1 && cqe->syndrome != SYNDROME_WR_FLUSH_ERR) {
-		int j;
-
-		mthca_dbg(dev, "%x/%d: error CQE -> QPN %06x, WQE @ %08x\n",
-			  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
-			  be32_to_cpu(cqe->wqe));
-
-		for (j = 0; j < 8; ++j)
-			printk(KERN_DEBUG "  [%2x] %08x\n",
-			       j * 4, be32_to_cpu(((u32 *) cqe)[j]));
+	if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) {
+		mthca_dbg(dev, "local QP operation err "
+			  "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n",
+			  be32_to_cpu(cqe->my_qpn), be32_to_cpu(cqe->wqe),
+			  cq->cqn, cq->cons_index);
+		dump_cqe(dev, cqe);
 	}
 
 	/*
@@ -377,15 +385,6 @@
 	return 0;
 }
 
-static void dump_cqe(struct mthca_cqe *cqe)
-{
-	int j;
-
-	for (j = 0; j < 8; ++j)
-		printk(KERN_DEBUG "  [%2x] %08x\n",
-		       j * 4, be32_to_cpu(((u32 *) cqe)[j]));
-}
-
 static inline int mthca_poll_one(struct mthca_dev *dev,
 				 struct mthca_cq *cq,
 				 struct mthca_qp **cur_qp,
@@ -414,8 +413,7 @@
 		mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
 			  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
 			  be32_to_cpu(cqe->wqe));
-
-		dump_cqe(cqe);
+		dump_cqe(dev, cqe);
 	}
 
 	is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
@@ -638,19 +636,19 @@
 	int size;
 
 	if (cq->is_direct)
-		pci_free_consistent(dev->pdev,
-				    (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
-				    cq->queue.direct.buf,
-				    pci_unmap_addr(&cq->queue.direct,
-						   mapping));
+		dma_free_coherent(&dev->pdev->dev,
+				  (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
+				  cq->queue.direct.buf,
+				  pci_unmap_addr(&cq->queue.direct,
+						 mapping));
 	else {
 		size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
 		for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
 			if (cq->queue.page_list[i].buf)
-				pci_free_consistent(dev->pdev, PAGE_SIZE,
-						    cq->queue.page_list[i].buf,
-						    pci_unmap_addr(&cq->queue.page_list[i],
-								   mapping));
+				dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+						  cq->queue.page_list[i].buf,
+						  pci_unmap_addr(&cq->queue.page_list[i],
+								 mapping));
 
 		kfree(cq->queue.page_list);
 	}
@@ -670,8 +668,8 @@
 		npages        = 1;
 		shift         = get_order(size) + PAGE_SHIFT;
 
-		cq->queue.direct.buf = pci_alloc_consistent(dev->pdev,
-							    size, &t);
+		cq->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
+							  size, &t, GFP_KERNEL);
 		if (!cq->queue.direct.buf)
 			return -ENOMEM;
 
@@ -709,7 +707,8 @@
 
 		for (i = 0; i < npages; ++i) {
 			cq->queue.page_list[i].buf =
-				pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
+				dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+						   &t, GFP_KERNEL);
 			if (!cq->queue.page_list[i].buf)
 				goto err_free;
 
@@ -746,7 +745,7 @@
 		  struct mthca_cq *cq)
 {
 	int size = nent * MTHCA_CQ_ENTRY_SIZE;
-	void *mailbox = NULL;
+	struct mthca_mailbox *mailbox;
 	struct mthca_cq_context *cq_context;
 	int err = -ENOMEM;
 	u8 status;
@@ -780,12 +779,11 @@
 			goto err_out_ci;
 	}
 
-	mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
-			  GFP_KERNEL);
-	if (!mailbox)
-		goto err_out_mailbox;
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		goto err_out_arm;
 
-	cq_context = MAILBOX_ALIGN(mailbox);
+	cq_context = mailbox->buf;
 
 	err = mthca_alloc_cq_buf(dev, size, cq);
 	if (err)
@@ -816,7 +814,7 @@
 		cq_context->state_db = cpu_to_be32(cq->arm_db_index);
 	}
 
-	err = mthca_SW2HW_CQ(dev, cq_context, cq->cqn, &status);
+	err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn, &status);
 	if (err) {
 		mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
 		goto err_out_free_mr;
@@ -840,7 +838,7 @@
 
 	cq->cons_index = 0;
 
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 
 	return 0;
 
@@ -849,8 +847,9 @@
 	mthca_free_cq_buf(dev, cq);
 
 err_out_mailbox:
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 
+err_out_arm:
 	if (mthca_is_memfree(dev))
 		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
 
@@ -870,28 +869,26 @@
 void mthca_free_cq(struct mthca_dev *dev,
 		   struct mthca_cq *cq)
 {
-	void *mailbox;
+	struct mthca_mailbox *mailbox;
 	int err;
 	u8 status;
 
 	might_sleep();
 
-	mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
-			  GFP_KERNEL);
-	if (!mailbox) {
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox)) {
 		mthca_warn(dev, "No memory for mailbox to free CQ.\n");
 		return;
 	}
 
-	err = mthca_HW2SW_CQ(dev, MAILBOX_ALIGN(mailbox), cq->cqn, &status);
+	err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn, &status);
 	if (err)
 		mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err);
 	else if (status)
-		mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n",
-			   status);
+		mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n", status);
 
 	if (0) {
-		u32 *ctx = MAILBOX_ALIGN(mailbox);
+		u32 *ctx = mailbox->buf;
 		int j;
 
 		printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
@@ -919,11 +916,11 @@
 	if (mthca_is_memfree(dev)) {
 		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
 		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
-		mthca_table_put(dev, dev->cq_table.table, cq->cqn);
 	}
 
+	mthca_table_put(dev, dev->cq_table.table, cq->cqn);
 	mthca_free(&dev->cq_table.alloc, cq->cqn);
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 }
 
 int __devinit mthca_init_cq_table(struct mthca_dev *dev)
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index e3d79e2..4127f09 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -46,8 +47,8 @@
 
 #define DRV_NAME	"ib_mthca"
 #define PFX		DRV_NAME ": "
-#define DRV_VERSION	"0.06-pre"
-#define DRV_RELDATE	"November 8, 2004"
+#define DRV_VERSION	"0.06"
+#define DRV_RELDATE	"June 23, 2005"
 
 enum {
 	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
@@ -98,6 +99,7 @@
 };
 
 struct mthca_cmd {
+	struct pci_pool          *pool;
 	int                       use_events;
 	struct semaphore          hcr_sem;
 	struct semaphore 	  poll_sem;
@@ -379,6 +381,12 @@
 int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
 void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
 
+struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
+void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt);
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+		    int start_index, u64 *buffer_list, int list_len);
+int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
+		   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr);
 int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 			   u32 access, struct mthca_mr *mr);
 int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
diff --git a/drivers/infiniband/hw/mthca/mthca_doorbell.h b/drivers/infiniband/hw/mthca/mthca_doorbell.h
index 821039a..535fad7 100644
--- a/drivers/infiniband/hw/mthca/mthca_doorbell.h
+++ b/drivers/infiniband/hw/mthca/mthca_doorbell.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index f46d615..cbcf2b4 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -469,7 +469,7 @@
 		PAGE_SIZE;
 	u64 *dma_list = NULL;
 	dma_addr_t t;
-	void *mailbox = NULL;
+	struct mthca_mailbox *mailbox;
 	struct mthca_eq_context *eq_context;
 	int err = -ENOMEM;
 	int i;
@@ -494,17 +494,16 @@
 	if (!dma_list)
 		goto err_out_free;
 
-	mailbox = kmalloc(sizeof *eq_context + MTHCA_CMD_MAILBOX_EXTRA,
-			  GFP_KERNEL);
-	if (!mailbox)
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
 		goto err_out_free;
-	eq_context = MAILBOX_ALIGN(mailbox);
+	eq_context = mailbox->buf;
 
 	for (i = 0; i < npages; ++i) {
-		eq->page_list[i].buf = pci_alloc_consistent(dev->pdev,
-							    PAGE_SIZE, &t);
+		eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
+							  PAGE_SIZE, &t, GFP_KERNEL);
 		if (!eq->page_list[i].buf)
-			goto err_out_free;
+			goto err_out_free_pages;
 
 		dma_list[i] = t;
 		pci_unmap_addr_set(&eq->page_list[i], mapping, t);
@@ -517,7 +516,7 @@
 
 	eq->eqn = mthca_alloc(&dev->eq_table.alloc);
 	if (eq->eqn == -1)
-		goto err_out_free;
+		goto err_out_free_pages;
 
 	err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
 				  dma_list, PAGE_SHIFT, npages,
@@ -548,7 +547,7 @@
 	eq_context->intr            = intr;
 	eq_context->lkey            = cpu_to_be32(eq->mr.ibmr.lkey);
 
-	err = mthca_SW2HW_EQ(dev, eq_context, eq->eqn, &status);
+	err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status);
 	if (err) {
 		mthca_warn(dev, "SW2HW_EQ failed (%d)\n", err);
 		goto err_out_free_mr;
@@ -561,7 +560,7 @@
 	}
 
 	kfree(dma_list);
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 
 	eq->eqn_mask   = swab32(1 << eq->eqn);
 	eq->cons_index = 0;
@@ -579,17 +578,19 @@
  err_out_free_eq:
 	mthca_free(&dev->eq_table.alloc, eq->eqn);
 
- err_out_free:
+ err_out_free_pages:
 	for (i = 0; i < npages; ++i)
 		if (eq->page_list[i].buf)
-			pci_free_consistent(dev->pdev, PAGE_SIZE,
-					    eq->page_list[i].buf,
-					    pci_unmap_addr(&eq->page_list[i],
-							   mapping));
+			dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+					  eq->page_list[i].buf,
+					  pci_unmap_addr(&eq->page_list[i],
+							 mapping));
 
+	mthca_free_mailbox(dev, mailbox);
+
+ err_out_free:
 	kfree(eq->page_list);
 	kfree(dma_list);
-	kfree(mailbox);
 
  err_out:
 	return err;
@@ -598,25 +599,22 @@
 static void mthca_free_eq(struct mthca_dev *dev,
 			  struct mthca_eq *eq)
 {
-	void *mailbox = NULL;
+	struct mthca_mailbox *mailbox;
 	int err;
 	u8 status;
 	int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
 		PAGE_SIZE;
 	int i;
 
-	mailbox = kmalloc(sizeof (struct mthca_eq_context) + MTHCA_CMD_MAILBOX_EXTRA,
-			  GFP_KERNEL);
-	if (!mailbox)
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
 		return;
 
-	err = mthca_HW2SW_EQ(dev, MAILBOX_ALIGN(mailbox),
-			     eq->eqn, &status);
+	err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status);
 	if (err)
 		mthca_warn(dev, "HW2SW_EQ failed (%d)\n", err);
 	if (status)
-		mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n",
-			   status);
+		mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n", status);
 
 	dev->eq_table.arm_mask &= ~eq->eqn_mask;
 
@@ -625,7 +623,7 @@
 		for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
 			if (i % 4 == 0)
 				printk("[%02x] ", i * 4);
-			printk(" %08x", be32_to_cpup(MAILBOX_ALIGN(mailbox) + i * 4));
+			printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
 			if ((i + 1) % 4 == 0)
 				printk("\n");
 		}
@@ -638,7 +636,7 @@
 				    pci_unmap_addr(&eq->page_list[i], mapping));
 
 	kfree(eq->page_list);
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 }
 
 static void mthca_free_irqs(struct mthca_dev *dev)
@@ -709,8 +707,7 @@
 		if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
 					dev->fw.arbel.eq_arm_base) + 4, 4,
 				  &dev->eq_regs.arbel.eq_arm)) {
-			mthca_err(dev, "Couldn't map interrupt clear register, "
-				  "aborting.\n");
+			mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
 			mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
 					dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
 					dev->clr_base);
@@ -721,8 +718,7 @@
 				  dev->fw.arbel.eq_set_ci_base,
 				  MTHCA_EQ_SET_CI_SIZE,
 				  &dev->eq_regs.arbel.eq_set_ci_base)) {
-			mthca_err(dev, "Couldn't map interrupt clear register, "
-				  "aborting.\n");
+			mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
 			mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
 					      dev->fw.arbel.eq_arm_base) + 4, 4,
 					dev->eq_regs.arbel.eq_arm);
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index d405903..09519b6 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -69,7 +70,7 @@
 #endif /* CONFIG_PCI_MSI */
 
 static const char mthca_version[] __devinitdata =
-	"ib_mthca: Mellanox InfiniBand HCA driver v"
+	DRV_NAME ": Mellanox InfiniBand HCA driver v"
 	DRV_VERSION " (" DRV_RELDATE ")\n";
 
 static struct mthca_profile default_profile = {
@@ -927,13 +928,13 @@
 	 */
 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
 	    pci_resource_len(pdev, 0) != 1 << 20) {
-		dev_err(&pdev->dev, "Missing DCS, aborting.");
+		dev_err(&pdev->dev, "Missing DCS, aborting.\n");
 		err = -ENODEV;
 		goto err_disable_pdev;
 	}
 	if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM) ||
 	    pci_resource_len(pdev, 2) != 1 << 23) {
-		dev_err(&pdev->dev, "Missing UAR, aborting.");
+		dev_err(&pdev->dev, "Missing UAR, aborting.\n");
 		err = -ENODEV;
 		goto err_disable_pdev;
 	}
@@ -1004,25 +1005,18 @@
 	    !pci_enable_msi(pdev))
 		mdev->mthca_flags |= MTHCA_FLAG_MSI;
 
-	sema_init(&mdev->cmd.hcr_sem, 1);
-	sema_init(&mdev->cmd.poll_sem, 1);
-	mdev->cmd.use_events = 0;
-
-	mdev->hcr = ioremap(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);
-	if (!mdev->hcr) {
-		mthca_err(mdev, "Couldn't map command register, "
-			  "aborting.\n");
-		err = -ENOMEM;
+	if (mthca_cmd_init(mdev)) {
+		mthca_err(mdev, "Failed to init command interface, aborting.\n");
 		goto err_free_dev;
 	}
 
 	err = mthca_tune_pci(mdev);
 	if (err)
-		goto err_iounmap;
+		goto err_cmd;
 
 	err = mthca_init_hca(mdev);
 	if (err)
-		goto err_iounmap;
+		goto err_cmd;
 
 	if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
 		mthca_warn(mdev, "HCA FW version %x.%x.%x is old (%x.%x.%x is current).\n",
@@ -1070,8 +1064,8 @@
 err_close:
 	mthca_close_hca(mdev);
 
-err_iounmap:
-	iounmap(mdev->hcr);
+err_cmd:
+	mthca_cmd_cleanup(mdev);
 
 err_free_dev:
 	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
@@ -1118,10 +1112,8 @@
 		iounmap(mdev->kar);
 		mthca_uar_free(mdev, &mdev->driver_uar);
 		mthca_cleanup_uar_table(mdev);
-
 		mthca_close_hca(mdev);
-
-		iounmap(mdev->hcr);
+		mthca_cmd_cleanup(mdev);
 
 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 			pci_disable_msix(pdev);
@@ -1163,7 +1155,7 @@
 MODULE_DEVICE_TABLE(pci, mthca_pci_table);
 
 static struct pci_driver mthca_driver = {
-	.name		= "ib_mthca",
+	.name		= DRV_NAME,
 	.id_table	= mthca_pci_table,
 	.probe		= mthca_init_one,
 	.remove		= __devexit_p(mthca_remove_one)
diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c
index 70a6553..5be7d94 100644
--- a/drivers/infiniband/hw/mthca/mthca_mcg.c
+++ b/drivers/infiniband/hw/mthca/mthca_mcg.c
@@ -66,22 +66,23 @@
  * entry in hash chain and *mgm holds end of hash chain.
  */
 static int find_mgm(struct mthca_dev *dev,
-		    u8 *gid, struct mthca_mgm *mgm,
+		    u8 *gid, struct mthca_mailbox *mgm_mailbox,
 		    u16 *hash, int *prev, int *index)
 {
-	void *mailbox;
+	struct mthca_mailbox *mailbox;
+	struct mthca_mgm *mgm = mgm_mailbox->buf;
 	u8 *mgid;
 	int err;
 	u8 status;
 
-	mailbox = kmalloc(16 + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-	if (!mailbox)
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
 		return -ENOMEM;
-	mgid = MAILBOX_ALIGN(mailbox);
+	mgid = mailbox->buf;
 
 	memcpy(mgid, gid, 16);
 
-	err = mthca_MGID_HASH(dev, mgid, hash, &status);
+	err = mthca_MGID_HASH(dev, mailbox, hash, &status);
 	if (err)
 		goto out;
 	if (status) {
@@ -103,7 +104,7 @@
 	*prev  = -1;
 
 	do {
-		err = mthca_READ_MGM(dev, *index, mgm, &status);
+		err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status);
 		if (err)
 			goto out;
 		if (status) {
@@ -129,14 +130,14 @@
 	*index = -1;
 
  out:
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
 	struct mthca_dev *dev = to_mdev(ibqp->device);
-	void *mailbox;
+	struct mthca_mailbox *mailbox;
 	struct mthca_mgm *mgm;
 	u16 hash;
 	int index, prev;
@@ -145,15 +146,15 @@
 	int err;
 	u8 status;
 
-	mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-	if (!mailbox)
-		return -ENOMEM;
-	mgm = MAILBOX_ALIGN(mailbox);
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	mgm = mailbox->buf;
 
 	if (down_interruptible(&dev->mcg_table.sem))
 		return -EINTR;
 
-	err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+	err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
 	if (err)
 		goto out;
 
@@ -170,7 +171,7 @@
 			goto out;
 		}
 
-		err = mthca_READ_MGM(dev, index, mgm, &status);
+		err = mthca_READ_MGM(dev, index, mailbox, &status);
 		if (err)
 			goto out;
 		if (status) {
@@ -195,7 +196,7 @@
 		goto out;
 	}
 
-	err = mthca_WRITE_MGM(dev, index, mgm, &status);
+	err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 	if (err)
 		goto out;
 	if (status) {
@@ -206,7 +207,7 @@
 	if (!link)
 		goto out;
 
-	err = mthca_READ_MGM(dev, prev, mgm, &status);
+	err = mthca_READ_MGM(dev, prev, mailbox, &status);
 	if (err)
 		goto out;
 	if (status) {
@@ -217,7 +218,7 @@
 
 	mgm->next_gid_index = cpu_to_be32(index << 5);
 
-	err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+	err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
 	if (err)
 		goto out;
 	if (status) {
@@ -227,14 +228,14 @@
 
  out:
 	up(&dev->mcg_table.sem);
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
 	struct mthca_dev *dev = to_mdev(ibqp->device);
-	void *mailbox;
+	struct mthca_mailbox *mailbox;
 	struct mthca_mgm *mgm;
 	u16 hash;
 	int prev, index;
@@ -242,15 +243,15 @@
 	int err;
 	u8 status;
 
-	mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-	if (!mailbox)
-		return -ENOMEM;
-	mgm = MAILBOX_ALIGN(mailbox);
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	mgm = mailbox->buf;
 
 	if (down_interruptible(&dev->mcg_table.sem))
 		return -EINTR;
 
-	err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+	err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
 	if (err)
 		goto out;
 
@@ -285,7 +286,7 @@
 	mgm->qp[loc]   = mgm->qp[i - 1];
 	mgm->qp[i - 1] = 0;
 
-	err = mthca_WRITE_MGM(dev, index, mgm, &status);
+	err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 	if (err)
 		goto out;
 	if (status) {
@@ -304,7 +305,7 @@
 		if (be32_to_cpu(mgm->next_gid_index) >> 5) {
 			err = mthca_READ_MGM(dev,
 					     be32_to_cpu(mgm->next_gid_index) >> 5,
-					     mgm, &status);
+					     mailbox, &status);
 			if (err)
 				goto out;
 			if (status) {
@@ -316,7 +317,7 @@
 		} else
 			memset(mgm->gid, 0, 16);
 
-		err = mthca_WRITE_MGM(dev, index, mgm, &status);
+		err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 		if (err)
 			goto out;
 		if (status) {
@@ -327,7 +328,7 @@
 	} else {
 		/* Remove entry from AMGM */
 		index = be32_to_cpu(mgm->next_gid_index) >> 5;
-		err = mthca_READ_MGM(dev, prev, mgm, &status);
+		err = mthca_READ_MGM(dev, prev, mailbox, &status);
 		if (err)
 			goto out;
 		if (status) {
@@ -338,7 +339,7 @@
 
 		mgm->next_gid_index = cpu_to_be32(index << 5);
 
-		err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+		err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
 		if (err)
 			goto out;
 		if (status) {
@@ -350,7 +351,7 @@
 
  out:
 	up(&dev->mcg_table.sem);
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 }
 
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 637b30e..6d3b05d 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -179,9 +179,14 @@
 
 void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
 {
-	int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+	int i;
 	u8 status;
 
+	if (!mthca_is_memfree(dev))
+		return;
+
+	i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+
 	down(&table->mutex);
 
 	if (--table->icm[i]->refcount == 0) {
@@ -256,6 +261,9 @@
 {
 	int i;
 
+	if (!mthca_is_memfree(dev))
+		return;
+
 	for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
 		mthca_table_put(dev, table, i);
 }
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 8960fc2..cbe50fe 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -40,6 +40,12 @@
 #include "mthca_cmd.h"
 #include "mthca_memfree.h"
 
+struct mthca_mtt {
+	struct mthca_buddy *buddy;
+	int                 order;
+	u32                 first_seg;
+};
+
 /*
  * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
  */
@@ -173,8 +179,8 @@
 	kfree(buddy->bits);
 }
 
-static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
-			   struct mthca_buddy *buddy)
+static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order,
+				 struct mthca_buddy *buddy)
 {
 	u32 seg = mthca_buddy_alloc(buddy, order);
 
@@ -191,14 +197,102 @@
 	return seg;
 }
 
-static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order,
-			   struct mthca_buddy* buddy)
+static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,
+					   struct mthca_buddy *buddy)
 {
-	mthca_buddy_free(buddy, seg, order);
+	struct mthca_mtt *mtt;
+	int i;
 
-	if (mthca_is_memfree(dev))
-		mthca_table_put_range(dev, dev->mr_table.mtt_table, seg,
-				      seg + (1 << order) - 1);
+	if (size <= 0)
+		return ERR_PTR(-EINVAL);
+
+	mtt = kmalloc(sizeof *mtt, GFP_KERNEL);
+	if (!mtt)
+		return ERR_PTR(-ENOMEM);
+
+	mtt->buddy = buddy;
+	mtt->order = 0;
+	for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)
+		++mtt->order;
+
+	mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);
+	if (mtt->first_seg == -1) {
+		kfree(mtt);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return mtt;
+}
+
+struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size)
+{
+	return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy);
+}
+
+void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt)
+{
+	if (!mtt)
+		return;
+
+	mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order);
+
+	mthca_table_put_range(dev, dev->mr_table.mtt_table,
+			      mtt->first_seg,
+			      mtt->first_seg + (1 << mtt->order) - 1);
+
+	kfree(mtt);
+}
+
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+		    int start_index, u64 *buffer_list, int list_len)
+{
+	struct mthca_mailbox *mailbox;
+	u64 *mtt_entry;
+	int err = 0;
+	u8 status;
+	int i;
+
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	mtt_entry = mailbox->buf;
+
+	while (list_len > 0) {
+		mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
+					   mtt->first_seg * MTHCA_MTT_SEG_SIZE +
+					   start_index * 8);
+		mtt_entry[1] = 0;
+		for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i)
+			mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
+						       MTHCA_MTT_FLAG_PRESENT);
+
+		/*
+		 * If we have an odd number of entries to write, add
+		 * one more dummy entry for firmware efficiency.
+		 */
+		if (i & 1)
+			mtt_entry[i + 2] = 0;
+
+		err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status);
+		if (err) {
+			mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
+			goto out;
+		}
+		if (status) {
+			mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
+				   status);
+			err = -EINVAL;
+			goto out;
+		}
+
+		list_len    -= i;
+		start_index += i;
+		buffer_list += i;
+	}
+
+out:
+	mthca_free_mailbox(dev, mailbox);
+	return err;
 }
 
 static inline u32 tavor_hw_index_to_key(u32 ind)
@@ -237,91 +331,18 @@
 		return tavor_key_to_hw_index(key);
 }
 
-int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
-			   u32 access, struct mthca_mr *mr)
+int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
+		   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
 {
-	void *mailbox = NULL;
+	struct mthca_mailbox *mailbox;
 	struct mthca_mpt_entry *mpt_entry;
 	u32 key;
+	int i;
 	int err;
 	u8 status;
 
 	might_sleep();
 
-	mr->order = -1;
-	key = mthca_alloc(&dev->mr_table.mpt_alloc);
-	if (key == -1)
-		return -ENOMEM;
-	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
-
-	if (mthca_is_memfree(dev)) {
-		err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
-		if (err)
-			goto err_out_mpt_free;
-	}
-
-	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
-			  GFP_KERNEL);
-	if (!mailbox) {
-		err = -ENOMEM;
-		goto err_out_table;
-	}
-	mpt_entry = MAILBOX_ALIGN(mailbox);
-
-	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
-				       MTHCA_MPT_FLAG_MIO         |
-				       MTHCA_MPT_FLAG_PHYSICAL    |
-				       MTHCA_MPT_FLAG_REGION      |
-				       access);
-	mpt_entry->page_size = 0;
-	mpt_entry->key       = cpu_to_be32(key);
-	mpt_entry->pd        = cpu_to_be32(pd);
-	mpt_entry->start     = 0;
-	mpt_entry->length    = ~0ULL;
-
-	memset(&mpt_entry->lkey, 0,
-	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
-
-	err = mthca_SW2HW_MPT(dev, mpt_entry,
-			      key & (dev->limits.num_mpts - 1),
-			      &status);
-	if (err) {
-		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
-		goto err_out_table;
-	} else if (status) {
-		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
-			   status);
-		err = -EINVAL;
-		goto err_out_table;
-	}
-
-	kfree(mailbox);
-	return err;
-
-err_out_table:
-	if (mthca_is_memfree(dev))
-		mthca_table_put(dev, dev->mr_table.mpt_table, key);
-
-err_out_mpt_free:
-	mthca_free(&dev->mr_table.mpt_alloc, key);
-	kfree(mailbox);
-	return err;
-}
-
-int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
-			u64 *buffer_list, int buffer_size_shift,
-			int list_len, u64 iova, u64 total_size,
-			u32 access, struct mthca_mr *mr)
-{
-	void *mailbox;
-	u64 *mtt_entry;
-	struct mthca_mpt_entry *mpt_entry;
-	u32 key;
-	int err = -ENOMEM;
-	u8 status;
-	int i;
-
-	might_sleep();
 	WARN_ON(buffer_size_shift >= 32);
 
 	key = mthca_alloc(&dev->mr_table.mpt_alloc);
@@ -335,75 +356,33 @@
 			goto err_out_mpt_free;
 	}
 
-	for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
-	     i < list_len;
-	     i <<= 1, ++mr->order)
-		; /* nothing */
-
-	mr->first_seg = mthca_alloc_mtt(dev, mr->order,
-				       	&dev->mr_table.mtt_buddy);
-	if (mr->first_seg == -1)
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox)) {
+		err = PTR_ERR(mailbox);
 		goto err_out_table;
-
-	/*
-	 * If list_len is odd, we add one more dummy entry for
-	 * firmware efficiency.
-	 */
-	mailbox = kmalloc(max(sizeof *mpt_entry,
-			      (size_t) 8 * (list_len + (list_len & 1) + 2)) +
-			  MTHCA_CMD_MAILBOX_EXTRA,
-			  GFP_KERNEL);
-	if (!mailbox)
-		goto err_out_free_mtt;
-
-	mtt_entry = MAILBOX_ALIGN(mailbox);
-
-	mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
-				   mr->first_seg * MTHCA_MTT_SEG_SIZE);
-	mtt_entry[1] = 0;
-	for (i = 0; i < list_len; ++i)
-		mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
-					       MTHCA_MTT_FLAG_PRESENT);
-	if (list_len & 1) {
-		mtt_entry[i + 2] = 0;
-		++list_len;
 	}
-
-	if (0) {
-		mthca_dbg(dev, "Dumping MPT entry\n");
-		for (i = 0; i < list_len + 2; ++i)
-			printk(KERN_ERR "[%2d] %016llx\n",
-			       i, (unsigned long long) be64_to_cpu(mtt_entry[i]));
-	}
-
-	err = mthca_WRITE_MTT(dev, mtt_entry, list_len, &status);
-	if (err) {
-		mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
-		goto err_out_mailbox_free;
-	}
-	if (status) {
-		mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
-			   status);
-		err = -EINVAL;
-		goto err_out_mailbox_free;
-	}
-
-	mpt_entry = MAILBOX_ALIGN(mailbox);
+	mpt_entry = mailbox->buf;
 
 	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 				       MTHCA_MPT_FLAG_MIO         |
 				       MTHCA_MPT_FLAG_REGION      |
 				       access);
+	if (!mr->mtt)
+		mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL);
 
 	mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
 	mpt_entry->key       = cpu_to_be32(key);
 	mpt_entry->pd        = cpu_to_be32(pd);
 	mpt_entry->start     = cpu_to_be64(iova);
 	mpt_entry->length    = cpu_to_be64(total_size);
+
 	memset(&mpt_entry->lkey, 0,
 	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
-	mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base +
-					   mr->first_seg * MTHCA_MTT_SEG_SIZE);
+
+	if (mr->mtt)
+		mpt_entry->mtt_seg =
+			cpu_to_be64(dev->mr_table.mtt_base +
+				    mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE);
 
 	if (0) {
 		mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
@@ -416,45 +395,70 @@
 		}
 	}
 
-	err = mthca_SW2HW_MPT(dev, mpt_entry,
+	err = mthca_SW2HW_MPT(dev, mailbox,
 			      key & (dev->limits.num_mpts - 1),
 			      &status);
-	if (err)
+	if (err) {
 		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
-	else if (status) {
+		goto err_out_mailbox;
+	} else if (status) {
 		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
 			   status);
 		err = -EINVAL;
+		goto err_out_mailbox;
 	}
 
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 	return err;
 
-err_out_mailbox_free:
-	kfree(mailbox);
-
-err_out_free_mtt:
-	mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy);
+err_out_mailbox:
+	mthca_free_mailbox(dev, mailbox);
 
 err_out_table:
-	if (mthca_is_memfree(dev))
-		mthca_table_put(dev, dev->mr_table.mpt_table, key);
+	mthca_table_put(dev, dev->mr_table.mpt_table, key);
 
 err_out_mpt_free:
 	mthca_free(&dev->mr_table.mpt_alloc, key);
 	return err;
 }
 
-/* Free mr or fmr */
-static void mthca_free_region(struct mthca_dev *dev, u32 lkey, int order,
-			      u32 first_seg, struct mthca_buddy *buddy)
+int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
+			   u32 access, struct mthca_mr *mr)
 {
-	if (order >= 0)
-		mthca_free_mtt(dev, first_seg, order, buddy);
+	mr->mtt = NULL;
+	return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr);
+}
 
-	if (mthca_is_memfree(dev))
-		mthca_table_put(dev, dev->mr_table.mpt_table,
-				arbel_key_to_hw_index(lkey));
+int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
+			u64 *buffer_list, int buffer_size_shift,
+			int list_len, u64 iova, u64 total_size,
+			u32 access, struct mthca_mr *mr)
+{
+	int err;
+
+	mr->mtt = mthca_alloc_mtt(dev, list_len);
+	if (IS_ERR(mr->mtt))
+		return PTR_ERR(mr->mtt);
+
+	err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len);
+	if (err) {
+		mthca_free_mtt(dev, mr->mtt);
+		return err;
+	}
+
+	err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova,
+			     total_size, access, mr);
+	if (err)
+		mthca_free_mtt(dev, mr->mtt);
+
+	return err;
+}
+
+/* Free mr or fmr */
+static void mthca_free_region(struct mthca_dev *dev, u32 lkey)
+{
+	mthca_table_put(dev, dev->mr_table.mpt_table,
+			arbel_key_to_hw_index(lkey));
 
 	mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
 }
@@ -476,15 +480,15 @@
 		mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
 			   status);
 
-	mthca_free_region(dev, mr->ibmr.lkey, mr->order, mr->first_seg,
-			  &dev->mr_table.mtt_buddy);
+	mthca_free_region(dev, mr->ibmr.lkey);
+	mthca_free_mtt(dev, mr->mtt);
 }
 
 int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 		    u32 access, struct mthca_fmr *mr)
 {
 	struct mthca_mpt_entry *mpt_entry;
-	void *mailbox;
+	struct mthca_mailbox *mailbox;
 	u64 mtt_seg;
 	u32 key, idx;
 	u8 status;
@@ -522,31 +526,24 @@
 		mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
 		       	sizeof *(mr->mem.tavor.mpt) * idx;
 
-	for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
-	     i < list_len;
-	     i <<= 1, ++mr->order)
-		; /* nothing */
-
-	mr->first_seg = mthca_alloc_mtt(dev, mr->order,
-				       	dev->mr_table.fmr_mtt_buddy);
-	if (mr->first_seg == -1)
+	mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
+	if (IS_ERR(mr->mtt))
 		goto err_out_table;
 
-	mtt_seg = mr->first_seg * MTHCA_MTT_SEG_SIZE;
+	mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
 
 	if (mthca_is_memfree(dev)) {
 		mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
-						      mr->first_seg);
+						      mr->mtt->first_seg);
 		BUG_ON(!mr->mem.arbel.mtts);
 	} else
 		mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
 
-	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
-			  GFP_KERNEL);
-	if (!mailbox)
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
 		goto err_out_free_mtt;
 
-	mpt_entry = MAILBOX_ALIGN(mailbox);
+	mpt_entry = mailbox->buf;
 
 	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 				       MTHCA_MPT_FLAG_MIO         |
@@ -571,7 +568,7 @@
 		}
 	}
 
-	err = mthca_SW2HW_MPT(dev, mpt_entry,
+	err = mthca_SW2HW_MPT(dev, mailbox,
 			      key & (dev->limits.num_mpts - 1),
 			      &status);
 	if (err) {
@@ -585,19 +582,17 @@
 		goto err_out_mailbox_free;
 	}
 
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 	return 0;
 
 err_out_mailbox_free:
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 
 err_out_free_mtt:
-	mthca_free_mtt(dev, mr->first_seg, mr->order,
-		       dev->mr_table.fmr_mtt_buddy);
+	mthca_free_mtt(dev, mr->mtt);
 
 err_out_table:
-	if (mthca_is_memfree(dev))
-		mthca_table_put(dev, dev->mr_table.mpt_table, key);
+	mthca_table_put(dev, dev->mr_table.mpt_table, key);
 
 err_out_mpt_free:
 	mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
@@ -609,8 +604,9 @@
 	if (fmr->maps)
 		return -EBUSY;
 
-	mthca_free_region(dev, fmr->ibmr.lkey, fmr->order, fmr->first_seg,
-			  dev->mr_table.fmr_mtt_buddy);
+	mthca_free_region(dev, fmr->ibmr.lkey);
+	mthca_free_mtt(dev, fmr->mtt);
+
 	return 0;
 }
 
@@ -826,7 +822,8 @@
 	if (dev->limits.reserved_mtts) {
 		i = fls(dev->limits.reserved_mtts - 1);
 
-		if (mthca_alloc_mtt(dev, i, dev->mr_table.fmr_mtt_buddy) == -1) {
+		if (mthca_alloc_mtt_range(dev, i,
+					  dev->mr_table.fmr_mtt_buddy) == -1) {
 			mthca_warn(dev, "MTT table of order %d is too small.\n",
 				  dev->mr_table.fmr_mtt_buddy->max_order);
 			err = -ENOMEM;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 159f4e6..0b5adfd 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -52,7 +53,7 @@
 	if (!in_mad || !out_mad)
 		goto out;
 
-	memset(props, 0, sizeof props);
+	memset(props, 0, sizeof *props);
 
 	props->fw_ver              = mdev->fw_ver;
 
@@ -558,6 +559,7 @@
 				  convert_access(acc), mr);
 
 	if (err) {
+		kfree(page_list);
 		kfree(mr);
 		return ERR_PTR(err);
 	}
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 619710f..4d976cc 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -54,18 +54,18 @@
 	int           index;
 };
 
+struct mthca_mtt;
+
 struct mthca_mr {
-	struct ib_mr ibmr;
-	int order;
-	u32 first_seg;
+	struct ib_mr      ibmr;
+	struct mthca_mtt *mtt;
 };
 
 struct mthca_fmr {
-	struct ib_fmr ibmr;
+	struct ib_fmr      ibmr;
 	struct ib_fmr_attr attr;
-	int order;
-	u32 first_seg;
-	int maps;
+	struct mthca_mtt  *mtt;
+	int                maps;
 	union {
 		struct {
 			struct mthca_mpt_entry __iomem *mpt;
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index ca73bab..163a8ef 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -357,6 +357,9 @@
 				[UD]  = (IB_QP_PKEY_INDEX |
 					 IB_QP_PORT       |
 					 IB_QP_QKEY),
+				[UC]  = (IB_QP_PKEY_INDEX |
+					 IB_QP_PORT       |
+					 IB_QP_ACCESS_FLAGS),
 				[RC]  = (IB_QP_PKEY_INDEX |
 					 IB_QP_PORT       |
 					 IB_QP_ACCESS_FLAGS),
@@ -378,6 +381,9 @@
 				[UD]  = (IB_QP_PKEY_INDEX |
 					 IB_QP_PORT       |
 					 IB_QP_QKEY),
+				[UC]  = (IB_QP_PKEY_INDEX |
+					 IB_QP_PORT       |
+					 IB_QP_ACCESS_FLAGS),
 				[RC]  = (IB_QP_PKEY_INDEX |
 					 IB_QP_PORT       |
 					 IB_QP_ACCESS_FLAGS),
@@ -388,6 +394,11 @@
 		[IB_QPS_RTR]   = {
 			.trans = MTHCA_TRANS_INIT2RTR,
 			.req_param = {
+				[UC]  = (IB_QP_AV                  |
+					 IB_QP_PATH_MTU            |
+					 IB_QP_DEST_QPN            |
+					 IB_QP_RQ_PSN              |
+					 IB_QP_MAX_DEST_RD_ATOMIC),
 				[RC]  = (IB_QP_AV                  |
 					 IB_QP_PATH_MTU            |
 					 IB_QP_DEST_QPN            |
@@ -398,6 +409,9 @@
 			.opt_param = {
 				[UD]  = (IB_QP_PKEY_INDEX |
 					 IB_QP_QKEY),
+				[UC]  = (IB_QP_ALT_PATH     |
+					 IB_QP_ACCESS_FLAGS |
+					 IB_QP_PKEY_INDEX),
 				[RC]  = (IB_QP_ALT_PATH     |
 					 IB_QP_ACCESS_FLAGS |
 					 IB_QP_PKEY_INDEX),
@@ -413,6 +427,8 @@
 			.trans = MTHCA_TRANS_RTR2RTS,
 			.req_param = {
 				[UD]  = IB_QP_SQ_PSN,
+				[UC]  = (IB_QP_SQ_PSN            |
+					 IB_QP_MAX_QP_RD_ATOMIC),
 				[RC]  = (IB_QP_TIMEOUT           |
 					 IB_QP_RETRY_CNT         |
 					 IB_QP_RNR_RETRY         |
@@ -423,6 +439,11 @@
 			.opt_param = {
 				[UD]  = (IB_QP_CUR_STATE             |
 					 IB_QP_QKEY),
+				[UC]  = (IB_QP_CUR_STATE             |
+					 IB_QP_ALT_PATH              |
+					 IB_QP_ACCESS_FLAGS          |
+					 IB_QP_PKEY_INDEX            |
+					 IB_QP_PATH_MIG_STATE),
 				[RC]  = (IB_QP_CUR_STATE             |
 					 IB_QP_ALT_PATH              |
 					 IB_QP_ACCESS_FLAGS          |
@@ -442,6 +463,9 @@
 			.opt_param = {
 				[UD]  = (IB_QP_CUR_STATE             |
 					 IB_QP_QKEY),
+				[UC]  = (IB_QP_ACCESS_FLAGS          |
+					 IB_QP_ALT_PATH              |
+					 IB_QP_PATH_MIG_STATE),
 				[RC]  = (IB_QP_ACCESS_FLAGS          |
 					 IB_QP_ALT_PATH              |
 					 IB_QP_PATH_MIG_STATE        |
@@ -462,6 +486,10 @@
 			.opt_param = {
 				[UD]  = (IB_QP_CUR_STATE             |
 					 IB_QP_QKEY),
+				[UC]  = (IB_QP_CUR_STATE             |
+					 IB_QP_ALT_PATH              |
+					 IB_QP_ACCESS_FLAGS          |
+					 IB_QP_PATH_MIG_STATE),
 				[RC]  = (IB_QP_CUR_STATE             |
 					 IB_QP_ALT_PATH              |
 					 IB_QP_ACCESS_FLAGS          |
@@ -476,6 +504,14 @@
 			.opt_param = {
 				[UD]  = (IB_QP_PKEY_INDEX            |
 					 IB_QP_QKEY),
+				[UC]  = (IB_QP_AV                    |
+					 IB_QP_MAX_QP_RD_ATOMIC      |
+					 IB_QP_MAX_DEST_RD_ATOMIC    |
+					 IB_QP_CUR_STATE             |
+					 IB_QP_ALT_PATH              |
+					 IB_QP_ACCESS_FLAGS          |
+					 IB_QP_PKEY_INDEX            |
+					 IB_QP_PATH_MIG_STATE),
 				[RC]  = (IB_QP_AV                    |
 					 IB_QP_TIMEOUT               |
 					 IB_QP_RETRY_CNT             |
@@ -501,6 +537,7 @@
 			.opt_param = {
 				[UD]  = (IB_QP_CUR_STATE             |
 					 IB_QP_QKEY),
+				[UC]  = (IB_QP_CUR_STATE),
 				[RC]  = (IB_QP_CUR_STATE             |
 					 IB_QP_MIN_RNR_TIMER),
 				[MLX] = (IB_QP_CUR_STATE             |
@@ -552,7 +589,7 @@
 	struct mthca_dev *dev = to_mdev(ibqp->device);
 	struct mthca_qp *qp = to_mqp(ibqp);
 	enum ib_qp_state cur_state, new_state;
-	void *mailbox = NULL;
+	struct mthca_mailbox *mailbox;
 	struct mthca_qp_param *qp_param;
 	struct mthca_qp_context *qp_context;
 	u32 req_param, opt_param;
@@ -609,10 +646,10 @@
 		return -EINVAL;
 	}
 
-	mailbox = kmalloc(sizeof (*qp_param) + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-	if (!mailbox)
-		return -ENOMEM;
-	qp_param = MAILBOX_ALIGN(mailbox);
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	qp_param = mailbox->buf;
 	qp_context = &qp_param->context;
 	memset(qp_param, 0, sizeof *qp_param);
 
@@ -683,7 +720,7 @@
 	if (attr_mask & IB_QP_AV) {
 		qp_context->pri_path.g_mylmc     = attr->ah_attr.src_path_bits & 0x7f;
 		qp_context->pri_path.rlid        = cpu_to_be16(attr->ah_attr.dlid);
-		qp_context->pri_path.static_rate = (!!attr->ah_attr.static_rate) << 3;
+		qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate;
 		if (attr->ah_attr.ah_flags & IB_AH_GRH) {
 			qp_context->pri_path.g_mylmc |= 1 << 7;
 			qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index;
@@ -724,9 +761,9 @@
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RETRY_COUNT);
 	}
 
-	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
-		qp_context->params1 |= cpu_to_be32(min(attr->max_dest_rd_atomic ?
-						       ffs(attr->max_dest_rd_atomic) - 1 : 0,
+	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+		qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ?
+						       ffs(attr->max_rd_atomic) - 1 : 0,
 						       7) << 21);
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX);
 	}
@@ -764,10 +801,10 @@
 		qp->atomic_rd_en = attr->qp_access_flags;
 	}
 
-	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
 		u8 rra_max;
 
-		if (qp->resp_depth && !attr->max_rd_atomic) {
+		if (qp->resp_depth && !attr->max_dest_rd_atomic) {
 			/*
 			 * Lowering our responder resources to zero.
 			 * Turn off RDMA/atomics as responder.
@@ -778,7 +815,7 @@
 								MTHCA_QP_OPTPAR_RAE);
 		}
 
-		if (!qp->resp_depth && attr->max_rd_atomic) {
+		if (!qp->resp_depth && attr->max_dest_rd_atomic) {
 			/*
 			 * Increasing our responder resources from
 			 * zero.  Turn on RDMA/atomics as appropriate.
@@ -799,7 +836,7 @@
 		}
 
 		for (rra_max = 0;
-		     1 << rra_max < attr->max_rd_atomic &&
+		     1 << rra_max < attr->max_dest_rd_atomic &&
 			     rra_max < dev->qp_table.rdb_shift;
 		     ++rra_max)
 			; /* nothing */
@@ -807,7 +844,7 @@
 		qp_context->params2      |= cpu_to_be32(rra_max << 21);
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX);
 
-		qp->resp_depth = attr->max_rd_atomic;
+		qp->resp_depth = attr->max_dest_rd_atomic;
 	}
 
 	qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
@@ -835,7 +872,7 @@
 	}
 
 	err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
-			      qp->qpn, 0, qp_param, 0, &status);
+			      qp->qpn, 0, mailbox, 0, &status);
 	if (status) {
 		mthca_warn(dev, "modify QP %d returned status %02x.\n",
 			   state_table[cur_state][new_state].trans, status);
@@ -845,7 +882,7 @@
 	if (!err)
 		qp->state = new_state;
 
-	kfree(mailbox);
+	mthca_free_mailbox(dev, mailbox);
 
 	if (is_sqp(dev, qp))
 		store_attrs(to_msqp(qp), attr, attr_mask);
@@ -934,7 +971,8 @@
 			mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
 				  size, shift);
 
-		qp->queue.direct.buf = pci_alloc_consistent(dev->pdev, size, &t);
+		qp->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev, size,
+							  &t, GFP_KERNEL);
 		if (!qp->queue.direct.buf)
 			goto err_out;
 
@@ -973,7 +1011,8 @@
 
 		for (i = 0; i < npages; ++i) {
 			qp->queue.page_list[i].buf =
-				pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
+				dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+						   &t, GFP_KERNEL);
 			if (!qp->queue.page_list[i].buf)
 				goto err_out_free;
 
@@ -996,16 +1035,15 @@
 
  err_out_free:
 	if (qp->is_direct) {
-		pci_free_consistent(dev->pdev, size,
-				    qp->queue.direct.buf,
-				    pci_unmap_addr(&qp->queue.direct, mapping));
+		dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
+				  pci_unmap_addr(&qp->queue.direct, mapping));
 	} else
 		for (i = 0; i < npages; ++i) {
 			if (qp->queue.page_list[i].buf)
-				pci_free_consistent(dev->pdev, PAGE_SIZE,
-						    qp->queue.page_list[i].buf,
-						    pci_unmap_addr(&qp->queue.page_list[i],
-								   mapping));
+				dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+						  qp->queue.page_list[i].buf,
+						  pci_unmap_addr(&qp->queue.page_list[i],
+								 mapping));
 
 		}
 
@@ -1073,11 +1111,12 @@
 	if (mthca_is_memfree(dev)) {
 		mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
 		mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
-		mthca_table_put(dev, dev->qp_table.rdb_table,
-				qp->qpn << dev->qp_table.rdb_shift);
-		mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
-		mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
 	}
+
+	mthca_table_put(dev, dev->qp_table.rdb_table,
+			qp->qpn << dev->qp_table.rdb_shift);
+	mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
+	mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
 }
 
 static void mthca_wq_init(struct mthca_wq* wq)
@@ -1529,6 +1568,26 @@
 
 			break;
 
+		case UC:
+			switch (wr->opcode) {
+			case IB_WR_RDMA_WRITE:
+			case IB_WR_RDMA_WRITE_WITH_IMM:
+				((struct mthca_raddr_seg *) wqe)->raddr =
+					cpu_to_be64(wr->wr.rdma.remote_addr);
+				((struct mthca_raddr_seg *) wqe)->rkey =
+					cpu_to_be32(wr->wr.rdma.rkey);
+				((struct mthca_raddr_seg *) wqe)->reserved = 0;
+				wqe += sizeof (struct mthca_raddr_seg);
+				size += sizeof (struct mthca_raddr_seg) / 16;
+				break;
+
+			default:
+				/* No extra segments required for sends */
+				break;
+			}
+
+			break;
+
 		case UD:
 			((struct mthca_tavor_ud_seg *) wqe)->lkey =
 				cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
@@ -1814,9 +1873,29 @@
 					sizeof (struct mthca_atomic_seg);
 				break;
 
+			case IB_WR_RDMA_READ:
 			case IB_WR_RDMA_WRITE:
 			case IB_WR_RDMA_WRITE_WITH_IMM:
-			case IB_WR_RDMA_READ:
+				((struct mthca_raddr_seg *) wqe)->raddr =
+					cpu_to_be64(wr->wr.rdma.remote_addr);
+				((struct mthca_raddr_seg *) wqe)->rkey =
+					cpu_to_be32(wr->wr.rdma.rkey);
+				((struct mthca_raddr_seg *) wqe)->reserved = 0;
+				wqe += sizeof (struct mthca_raddr_seg);
+				size += sizeof (struct mthca_raddr_seg) / 16;
+				break;
+
+			default:
+				/* No extra segments required for sends */
+				break;
+			}
+
+			break;
+
+		case UC:
+			switch (wr->opcode) {
+			case IB_WR_RDMA_WRITE:
+			case IB_WR_RDMA_WRITE_WITH_IMM:
 				((struct mthca_raddr_seg *) wqe)->raddr =
 					cpu_to_be64(wr->wr.rdma.remote_addr);
 				((struct mthca_raddr_seg *) wqe)->rkey =
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 556264b..374f404 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -21,6 +21,7 @@
 #include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/compat.h>
 
 struct evdev {
 	int exist;
@@ -145,6 +146,41 @@
 	return 0;
 }
 
+#ifdef CONFIG_COMPAT
+struct input_event_compat {
+	struct compat_timeval time;
+	__u16 type;
+	__u16 code;
+	__s32 value;
+};
+
+#ifdef CONFIG_X86_64
+#  define COMPAT_TEST test_thread_flag(TIF_IA32)
+#elif defined(CONFIG_IA64)
+#  define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
+#elif defined(CONFIG_ARCH_S390)
+#  define COMPAT_TEST test_thread_flag(TIF_31BIT)
+#else
+#  define COMPAT_TEST test_thread_flag(TIF_32BIT)
+#endif
+
+static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+{
+	struct evdev_list *list = file->private_data;
+	struct input_event_compat event;
+	int retval = 0;
+
+	while (retval < count) {
+		if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
+			return -EFAULT;
+		input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+		retval += sizeof(struct input_event_compat);
+	}
+
+	return retval;
+}
+#endif
+
 static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 {
 	struct evdev_list *list = file->private_data;
@@ -153,6 +189,11 @@
 
 	if (!list->evdev->exist) return -ENODEV;
 
+#ifdef CONFIG_COMPAT
+	if (COMPAT_TEST)
+		return evdev_write_compat(file, buffer, count, ppos);
+#endif
+
 	while (retval < count) {
 
 		if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
@@ -164,11 +205,56 @@
 	return retval;
 }
 
+#ifdef CONFIG_COMPAT
+static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+{
+	struct evdev_list *list = file->private_data;
+	int retval;
+
+	if (count < sizeof(struct input_event_compat))
+		return -EINVAL;
+
+	if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	retval = wait_event_interruptible(list->evdev->wait,
+		list->head != list->tail || (!list->evdev->exist));
+
+	if (retval)
+		return retval;
+
+	if (!list->evdev->exist)
+		return -ENODEV;
+
+	while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) {
+		struct input_event *event = (struct input_event *) list->buffer + list->tail;
+		struct input_event_compat event_compat;
+		event_compat.time.tv_sec = event->time.tv_sec;
+		event_compat.time.tv_usec = event->time.tv_usec;
+		event_compat.type = event->type;
+		event_compat.code = event->code;
+		event_compat.value = event->value;
+
+		if (copy_to_user(buffer + retval, &event_compat,
+			sizeof(struct input_event_compat))) return -EFAULT;
+		list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+		retval += sizeof(struct input_event_compat);
+	}
+
+	return retval;
+}
+#endif
+
 static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 {
 	struct evdev_list *list = file->private_data;
 	int retval;
 
+#ifdef CONFIG_COMPAT
+	if (COMPAT_TEST)
+		return evdev_read_compat(file, buffer, count, ppos);
+#endif
+
 	if (count < sizeof(struct input_event))
 		return -EINVAL;
 
@@ -186,7 +272,7 @@
 
 	while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
 		if (copy_to_user(buffer + retval, list->buffer + list->tail,
-			 sizeof(struct input_event))) return -EFAULT;
+			sizeof(struct input_event))) return -EFAULT;
 		list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
 		retval += sizeof(struct input_event);
 	}
@@ -203,7 +289,7 @@
 		(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
-static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct evdev_list *list = file->private_data;
 	struct evdev *evdev = list->evdev;
@@ -285,110 +371,268 @@
 
 		default:
 
-			if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+			if (_IOC_TYPE(cmd) != 'E')
 				return -EINVAL;
 
-			if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+			if (_IOC_DIR(cmd) == _IOC_READ) {
 
-				long *bits;
-				int len;
+				if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 
-				switch (_IOC_NR(cmd) & EV_MAX) {
-					case      0: bits = dev->evbit;  len = EV_MAX;  break;
-					case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
-					case EV_REL: bits = dev->relbit; len = REL_MAX; break;
-					case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
-					case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
-					case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
-					case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
-					case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
-					default: return -EINVAL;
+					long *bits;
+					int len;
+
+					switch (_IOC_NR(cmd) & EV_MAX) {
+						case      0: bits = dev->evbit;  len = EV_MAX;  break;
+						case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+						case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+						case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+						case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+						case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+						case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+						case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
+						default: return -EINVAL;
+					}
+					len = NBITS(len) * sizeof(long);
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, bits, len) ? -EFAULT : len;
 				}
-				len = NBITS(len) * sizeof(long);
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				return copy_to_user(p, bits, len) ? -EFAULT : len;
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
+					int len;
+					len = NBITS(KEY_MAX) * sizeof(long);
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->key, len) ? -EFAULT : len;
+				}
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
+					int len;
+					len = NBITS(LED_MAX) * sizeof(long);
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->led, len) ? -EFAULT : len;
+				}
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
+					int len;
+					len = NBITS(SND_MAX) * sizeof(long);
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
+				}
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+					int len;
+					if (!dev->name) return -ENOENT;
+					len = strlen(dev->name) + 1;
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->name, len) ? -EFAULT : len;
+				}
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+					int len;
+					if (!dev->phys) return -ENOENT;
+					len = strlen(dev->phys) + 1;
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
+				}
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+					int len;
+					if (!dev->uniq) return -ENOENT;
+					len = strlen(dev->uniq) + 1;
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+				}
+
+				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+					int t = _IOC_NR(cmd) & ABS_MAX;
+
+					abs.value = dev->abs[t];
+					abs.minimum = dev->absmin[t];
+					abs.maximum = dev->absmax[t];
+					abs.fuzz = dev->absfuzz[t];
+					abs.flat = dev->absflat[t];
+
+					if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+						return -EFAULT;
+
+					return 0;
+				}
+
 			}
 
-			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
-				int len;
-				len = NBITS(KEY_MAX) * sizeof(long);
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				return copy_to_user(p, dev->key, len) ? -EFAULT : len;
-			}
+			if (_IOC_DIR(cmd) == _IOC_WRITE) {
 
-			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
-				int len;
-				len = NBITS(LED_MAX) * sizeof(long);
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				return copy_to_user(p, dev->led, len) ? -EFAULT : len;
-			}
+				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 
-			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
-				int len;
-				len = NBITS(SND_MAX) * sizeof(long);
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
-			}
+					int t = _IOC_NR(cmd) & ABS_MAX;
 
-			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
-				int len;
-				if (!dev->name) return -ENOENT;
-				len = strlen(dev->name) + 1;
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				return copy_to_user(p, dev->name, len) ? -EFAULT : len;
-			}
+					if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+						return -EFAULT;
 
-			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
-				int len;
-				if (!dev->phys) return -ENOENT;
-				len = strlen(dev->phys) + 1;
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
-			}
+					dev->abs[t] = abs.value;
+					dev->absmin[t] = abs.minimum;
+					dev->absmax[t] = abs.maximum;
+					dev->absfuzz[t] = abs.fuzz;
+					dev->absflat[t] = abs.flat;
 
-			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
-				int len;
-				if (!dev->uniq) return -ENOENT;
-				len = strlen(dev->uniq) + 1;
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
-			}
-
-			if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
-
-				int t = _IOC_NR(cmd) & ABS_MAX;
-
-				abs.value = dev->abs[t];
-				abs.minimum = dev->absmin[t];
-				abs.maximum = dev->absmax[t];
-				abs.fuzz = dev->absfuzz[t];
-				abs.flat = dev->absflat[t];
-
-				if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
-					return -EFAULT;
-
-				return 0;
-			}
-
-			if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
-
-				int t = _IOC_NR(cmd) & ABS_MAX;
-
-				if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
-					return -EFAULT;
-
-				dev->abs[t] = abs.value;
-				dev->absmin[t] = abs.minimum;
-				dev->absmax[t] = abs.maximum;
-				dev->absfuzz[t] = abs.fuzz;
-				dev->absflat[t] = abs.flat;
-
-				return 0;
+					return 0;
+				}
 			}
 	}
 	return -EINVAL;
 }
 
+#ifdef CONFIG_COMPAT
+
+#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
+#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1)
+#define OFF_COMPAT(x)  ((x)%BITS_PER_LONG_COMPAT)
+#define BIT_COMPAT(x)  (1UL<<OFF_COMPAT(x))
+#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT)
+#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1)
+
+#ifdef __BIG_ENDIAN
+#define bit_to_user(bit, max) \
+do { \
+	int i; \
+	int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
+	if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
+	for (i = 0; i < len / sizeof(compat_long_t); i++) \
+		if (copy_to_user((compat_long_t*) p + i, \
+				 (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \
+				 sizeof(compat_long_t))) \
+			return -EFAULT; \
+	return len; \
+} while (0)
+#else
+#define bit_to_user(bit, max) \
+do { \
+	int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
+	if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
+	return copy_to_user(p, (bit), len) ? -EFAULT : len; \
+} while (0)
+#endif
+
+static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct evdev_list *list = file->private_data;
+	struct evdev *evdev = list->evdev;
+	struct input_dev *dev = evdev->handle.dev;
+	struct input_absinfo abs;
+	void __user *p = compat_ptr(arg);
+
+	if (!evdev->exist) return -ENODEV;
+
+	switch (cmd) {
+
+		case EVIOCGVERSION:
+		case EVIOCGID:
+		case EVIOCGKEYCODE:
+		case EVIOCSKEYCODE:
+		case EVIOCSFF:
+		case EVIOCRMFF:
+		case EVIOCGEFFECTS:
+		case EVIOCGRAB:
+			return evdev_ioctl(file, cmd, (unsigned long) p);
+
+		default:
+
+			if (_IOC_TYPE(cmd) != 'E')
+				return -EINVAL;
+
+			if (_IOC_DIR(cmd) == _IOC_READ) {
+
+				if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+					long *bits;
+					int max;
+
+					switch (_IOC_NR(cmd) & EV_MAX) {
+						case      0: bits = dev->evbit;  max = EV_MAX;  break;
+						case EV_KEY: bits = dev->keybit; max = KEY_MAX; break;
+						case EV_REL: bits = dev->relbit; max = REL_MAX; break;
+						case EV_ABS: bits = dev->absbit; max = ABS_MAX; break;
+						case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break;
+						case EV_LED: bits = dev->ledbit; max = LED_MAX; break;
+						case EV_SND: bits = dev->sndbit; max = SND_MAX; break;
+						case EV_FF:  bits = dev->ffbit;  max = FF_MAX;  break;
+						default: return -EINVAL;
+					}
+					bit_to_user(bits, max);
+				}
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+					bit_to_user(dev->key, KEY_MAX);
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+					bit_to_user(dev->led, LED_MAX);
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+					bit_to_user(dev->snd, SND_MAX);
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+					int len;
+					if (!dev->name) return -ENOENT;
+					len = strlen(dev->name) + 1;
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->name, len) ? -EFAULT : len;
+				}
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+					int len;
+					if (!dev->phys) return -ENOENT;
+					len = strlen(dev->phys) + 1;
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
+				}
+
+				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+					int len;
+					if (!dev->uniq) return -ENOENT;
+					len = strlen(dev->uniq) + 1;
+					if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+					return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+				}
+
+				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+					int t = _IOC_NR(cmd) & ABS_MAX;
+
+					abs.value = dev->abs[t];
+					abs.minimum = dev->absmin[t];
+					abs.maximum = dev->absmax[t];
+					abs.fuzz = dev->absfuzz[t];
+					abs.flat = dev->absflat[t];
+
+					if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+						return -EFAULT;
+
+					return 0;
+				}
+			}
+
+			if (_IOC_DIR(cmd) == _IOC_WRITE) {
+
+				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+
+					int t = _IOC_NR(cmd) & ABS_MAX;
+
+					if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+						return -EFAULT;
+
+					dev->abs[t] = abs.value;
+					dev->absmin[t] = abs.minimum;
+					dev->absmax[t] = abs.maximum;
+					dev->absfuzz[t] = abs.fuzz;
+					dev->absflat[t] = abs.flat;
+
+					return 0;
+				}
+			}
+	}
+	return -EINVAL;
+}
+#endif
+
 static struct file_operations evdev_fops = {
 	.owner =	THIS_MODULE,
 	.read =		evdev_read,
@@ -396,7 +640,10 @@
 	.poll =		evdev_poll,
 	.open =		evdev_open,
 	.release =	evdev_release,
-	.ioctl =	evdev_ioctl,
+	.unlocked_ioctl = evdev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl =	evdev_ioctl_compat,
+#endif
 	.fasync =	evdev_fasync,
 	.flush =	evdev_flush
 };
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
index 1d93f50..7524bd7 100644
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -49,22 +49,8 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called emu10k1-gp.
 
-config GAMEPORT_VORTEX
-	tristate "Aureal Vortex, Vortex 2 gameport support"
-	depends on PCI
-	help
-	  Say Y here if you have an Aureal Vortex 1 or 2  card and want
-	  to use its gameport.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called vortex.
-
 config GAMEPORT_FM801
 	tristate "ForteMedia FM801 gameport support"
 	depends on PCI
 
-config GAMEPORT_CS461X
-	tristate "Crystal SoundFusion gameport support"
-	depends on PCI
-
 endif
diff --git a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
index 5367b42..b6f6097 100644
--- a/drivers/input/gameport/Makefile
+++ b/drivers/input/gameport/Makefile
@@ -5,9 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_GAMEPORT)		+= gameport.o
-obj-$(CONFIG_GAMEPORT_CS461X)	+= cs461x.o
 obj-$(CONFIG_GAMEPORT_EMU10K1)	+= emu10k1-gp.o
 obj-$(CONFIG_GAMEPORT_FM801)	+= fm801-gp.o
 obj-$(CONFIG_GAMEPORT_L4)	+= lightning.o
 obj-$(CONFIG_GAMEPORT_NS558)	+= ns558.o
-obj-$(CONFIG_GAMEPORT_VORTEX)	+= vortex.o
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
deleted file mode 100644
index d4013ff..0000000
--- a/drivers/input/gameport/cs461x.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
-	The all defines and part of code (such as cs461x_*) are
-	contributed from ALSA 0.5.8 sources.
-	See http://www.alsa-project.org/ for sources
-
-	Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
-*/
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Victor Krapivin");
-MODULE_LICENSE("GPL");
-
-/*
-	These options are experimental
-
-#define CS461X_FULL_MAP
-*/
-
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS            0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4610
-#define PCI_DEVICE_ID_CIRRUS_4610       0x6001
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4612
-#define PCI_DEVICE_ID_CIRRUS_4612       0x6003
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4615
-#define PCI_DEVICE_ID_CIRRUS_4615       0x6004
-#endif
-
-/* Registers */
-
-#define BA0_JSPT                                0x00000480
-#define BA0_JSCTL                               0x00000484
-#define BA0_JSC1                                0x00000488
-#define BA0_JSC2                                0x0000048C
-#define BA0_JSIO                                0x000004A0
-
-/* Bits for JSPT */
-
-#define JSPT_CAX                                0x00000001
-#define JSPT_CAY                                0x00000002
-#define JSPT_CBX                                0x00000004
-#define JSPT_CBY                                0x00000008
-#define JSPT_BA1                                0x00000010
-#define JSPT_BA2                                0x00000020
-#define JSPT_BB1                                0x00000040
-#define JSPT_BB2                                0x00000080
-
-/* Bits for JSCTL */
-
-#define JSCTL_SP_MASK                           0x00000003
-#define JSCTL_SP_SLOW                           0x00000000
-#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
-#define JSCTL_SP_MEDIUM_FAST                    0x00000002
-#define JSCTL_SP_FAST                           0x00000003
-#define JSCTL_ARE                               0x00000004
-
-/* Data register pairs masks */
-
-#define JSC1_Y1V_MASK                           0x0000FFFF
-#define JSC1_X1V_MASK                           0xFFFF0000
-#define JSC1_Y1V_SHIFT                          0
-#define JSC1_X1V_SHIFT                          16
-#define JSC2_Y2V_MASK                           0x0000FFFF
-#define JSC2_X2V_MASK                           0xFFFF0000
-#define JSC2_Y2V_SHIFT                          0
-#define JSC2_X2V_SHIFT                          16
-
-/* JS GPIO */
-
-#define JSIO_DAX                                0x00000001
-#define JSIO_DAY                                0x00000002
-#define JSIO_DBX                                0x00000004
-#define JSIO_DBY                                0x00000008
-#define JSIO_AXOE                               0x00000010
-#define JSIO_AYOE                               0x00000020
-#define JSIO_BXOE                               0x00000040
-#define JSIO_BYOE                               0x00000080
-
-/*
-   The card initialization code is obfuscated; the module cs461x
-   need to be loaded after ALSA modules initialized and something
-   played on the CS 4610 chip (see sources for details of CS4610
-   initialization code from ALSA)
-*/
-
-/* Card specific definitions */
-
-#define CS461X_BA0_SIZE         0x2000
-#define CS461X_BA1_DATA0_SIZE   0x3000
-#define CS461X_BA1_DATA1_SIZE   0x3800
-#define CS461X_BA1_PRG_SIZE     0x7000
-#define CS461X_BA1_REG_SIZE     0x0100
-
-#define BA1_SP_DMEM0                            0x00000000
-#define BA1_SP_DMEM1                            0x00010000
-#define BA1_SP_PMEM                             0x00020000
-#define BA1_SP_REG                              0x00030000
-
-#define BA1_DWORD_SIZE          (13 * 1024 + 512)
-#define BA1_MEMORY_COUNT        3
-
-/*
-   Only one CS461x card is still suppoted; the code requires
-   redesign to avoid this limitatuion.
-*/
-
-static unsigned long ba0_addr;
-static unsigned int __iomem *ba0;
-
-#ifdef CS461X_FULL_MAP
-static unsigned long ba1_addr;
-static union ba1_t {
-        struct {
-                unsigned int __iomem *data0;
-                unsigned int __iomem *data1;
-                unsigned int __iomem *pmem;
-                unsigned int __iomem *reg;
-        } name;
-        unsigned int __iomem *idx[4];
-} ba1;
-
-static void cs461x_poke(unsigned long reg, unsigned int val)
-{
-        writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-static unsigned int cs461x_peek(unsigned long reg)
-{
-        return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-#endif
-
-static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
-{
-        writel(val, &ba0[reg >> 2]);
-}
-
-static unsigned int cs461x_peekBA0(unsigned long reg)
-{
-        return readl(&ba0[reg >> 2]);
-}
-
-static int cs461x_free(struct pci_dev *pdev)
-{
-	struct gameport *port = pci_get_drvdata(pdev);
-
-	if (port)
-	    gameport_unregister_port(port);
-
-	if (ba0) iounmap(ba0);
-#ifdef CS461X_FULL_MAP
-	if (ba1.name.data0) iounmap(ba1.name.data0);
-	if (ba1.name.data1) iounmap(ba1.name.data1);
-	if (ba1.name.pmem)  iounmap(ba1.name.pmem);
-	if (ba1.name.reg)   iounmap(ba1.name.reg);
-#endif
-	return 0;
-}
-
-static void cs461x_gameport_trigger(struct gameport *gameport)
-{
-	cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
-}
-
-static unsigned char cs461x_gameport_read(struct gameport *gameport)
-{
-	return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
-}
-
-static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
-	unsigned js1, js2, jst;
-
-	js1 = cs461x_peekBA0(BA0_JSC1);
-	js2 = cs461x_peekBA0(BA0_JSC2);
-	jst = cs461x_peekBA0(BA0_JSPT);
-
-	*buttons = (~jst >> 4) & 0x0F;
-
-	axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
-	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
-	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
-	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
-
-	for(jst=0;jst<4;++jst)
-		if(axes[jst]==0xFFFF) axes[jst] = -1;
-	return 0;
-}
-
-static int cs461x_gameport_open(struct gameport *gameport, int mode)
-{
-	switch (mode) {
-		case GAMEPORT_MODE_COOKED:
-		case GAMEPORT_MODE_RAW:
-			return 0;
-		default:
-			return -1;
-	}
-	return 0;
-}
-
-static struct pci_device_id cs461x_pci_tbl[] = {
-	{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
-	{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
-	{ PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
-	{ 0, }
-};
-MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
-
-static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	int rc;
-	struct gameport* port;
-
-	rc = pci_enable_device(pdev);
-	if (rc) {
-		printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
-			pdev->bus->number, pdev->devfn, rc);
-		return rc;
-	}
-
-	ba0_addr = pci_resource_start(pdev, 0);
-#ifdef CS461X_FULL_MAP
-	ba1_addr = pci_resource_start(pdev, 1);
-#endif
-	if (ba0_addr == 0 || ba0_addr == ~0
-#ifdef CS461X_FULL_MAP
-            || ba1_addr == 0 || ba1_addr == ~0
-#endif
-	    ) {
-                printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
-#ifdef CS461X_FULL_MAP
-                printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
-#endif
-		cs461x_free(pdev);
-                return -ENOMEM;
-        }
-
-	ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
-#ifdef CS461X_FULL_MAP
-	ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
-	ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
-	ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
-	ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-
-	if (ba0 == NULL || ba1.name.data0 == NULL ||
-            ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
-            ba1.name.reg == NULL) {
-		cs461x_free(pdev);
-                return -ENOMEM;
-        }
-#else
-	if (ba0 == NULL) {
-		cs461x_free(pdev);
-		return -ENOMEM;
-	}
-#endif
-
-	if (!(port = gameport_allocate_port())) {
-		printk(KERN_ERR "cs461x: Memory allocation failed\n");
-		cs461x_free(pdev);
-		return -ENOMEM;
-	}
-
-	pci_set_drvdata(pdev, port);
-
-	port->open = cs461x_gameport_open;
-	port->trigger = cs461x_gameport_trigger;
-	port->read = cs461x_gameport_read;
-	port->cooked_read = cs461x_gameport_cooked_read;
-
-	gameport_set_name(port, "CS416x");
-	gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
-	port->dev.parent = &pdev->dev;
-
-	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
-	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-
-	gameport_register_port(port);
-
-	return 0;
-}
-
-static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
-{
-	cs461x_free(pdev);
-}
-
-static struct pci_driver cs461x_pci_driver = {
-        .name =         "CS461x_gameport",
-        .id_table =     cs461x_pci_tbl,
-        .probe =        cs461x_pci_probe,
-        .remove =       __devexit_p(cs461x_pci_remove),
-};
-
-static int __init cs461x_init(void)
-{
-        return pci_register_driver(&cs461x_pci_driver);
-}
-
-static void __exit cs461x_exit(void)
-{
-        pci_unregister_driver(&cs461x_pci_driver);
-}
-
-module_init(cs461x_init);
-module_exit(cs461x_exit);
-
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 7c5c631..1ab5f2d 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -258,18 +258,18 @@
 {
 	int i = 0;
 
+	if (pnp_register_driver(&ns558_pnp_driver) >= 0)
+		pnp_registered = 1;
+
 /*
- * Probe ISA ports first so that PnP gets to choose free port addresses
- * not occupied by the ISA ports.
+ * Probe ISA ports after PnP, so that PnP ports that are already
+ * enabled get detected as PnP. This may be suboptimal in multi-device
+ * configurations, but saves hassle with simple setups.
  */
 
 	while (ns558_isa_portlist[i])
 		ns558_isa_probe(ns558_isa_portlist[i++]);
 
-	if (pnp_register_driver(&ns558_pnp_driver) >= 0)
-		pnp_registered = 1;
-
-
 	return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
 }
 
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
deleted file mode 100644
index 36b0309..0000000
--- a/drivers/input/gameport/vortex.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
- *
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Raymond Ingles
- */
-
-/*
- * Trident 4DWave and Aureal Vortex gameport driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/gameport.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
-MODULE_LICENSE("GPL");
-
-#define VORTEX_GCR		0x0c	/* Gameport control register */
-#define VORTEX_LEG		0x08	/* Legacy port location */
-#define VORTEX_AXD		0x10	/* Axes start */
-#define VORTEX_DATA_WAIT	20	/* 20 ms */
-
-struct vortex {
-	struct gameport *gameport;
-	struct pci_dev *dev;
-	unsigned char __iomem *base;
-	unsigned char __iomem *io;
-};
-
-static unsigned char vortex_read(struct gameport *gameport)
-{
-	struct vortex *vortex = gameport->port_data;
-	return readb(vortex->io + VORTEX_LEG);
-}
-
-static void vortex_trigger(struct gameport *gameport)
-{
-	struct vortex *vortex = gameport->port_data;
-	writeb(0xff, vortex->io + VORTEX_LEG);
-}
-
-static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
-	struct vortex *vortex = gameport->port_data;
-	int i;
-
-	*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
-
-	for (i = 0; i < 4; i++) {
-		axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
-		if (axes[i] == 0x1fff) axes[i] = -1;
-	}
-
-        return 0;
-}
-
-static int vortex_open(struct gameport *gameport, int mode)
-{
-	struct vortex *vortex = gameport->port_data;
-
-	switch (mode) {
-		case GAMEPORT_MODE_COOKED:
-			writeb(0x40, vortex->io + VORTEX_GCR);
-			msleep(VORTEX_DATA_WAIT);
-			return 0;
-		case GAMEPORT_MODE_RAW:
-			writeb(0x00, vortex->io + VORTEX_GCR);
-			return 0;
-		default:
-			return -1;
-	}
-
-	return 0;
-}
-
-static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-	struct vortex *vortex;
-	struct gameport *port;
-	int i;
-
-	vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
-	port = gameport_allocate_port();
-	if (!vortex || !port) {
-		printk(KERN_ERR "vortex: Memory allocation failed.\n");
-		kfree(vortex);
-		gameport_free_port(port);
-		return -ENOMEM;
-	}
-
-	for (i = 0; i < 6; i++)
-		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
-			break;
-
-	pci_enable_device(dev);
-
-	vortex->dev = dev;
-	vortex->gameport = port;
-	vortex->base = ioremap(pci_resource_start(vortex->dev, i),
-				pci_resource_len(vortex->dev, i));
-	vortex->io = vortex->base + id->driver_data;
-
-	pci_set_drvdata(dev, vortex);
-
-	port->port_data = vortex;
-	port->fuzz = 64;
-
-	gameport_set_name(port, "AU88x0");
-	gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
-	port->dev.parent = &dev->dev;
-	port->read = vortex_read;
-	port->trigger = vortex_trigger;
-	port->cooked_read = vortex_cooked_read;
-	port->open = vortex_open;
-
-	gameport_register_port(port);
-
-	return 0;
-}
-
-static void __devexit vortex_remove(struct pci_dev *dev)
-{
-	struct vortex *vortex = pci_get_drvdata(dev);
-
-	gameport_unregister_port(vortex->gameport);
-	iounmap(vortex->base);
-	kfree(vortex);
-}
-
-static struct pci_device_id vortex_id_table[] = {
-	{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
-	{ 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
-	{ 0 }
-};
-
-static struct pci_driver vortex_driver = {
-	.name =		"vortex_gameport",
-	.id_table =	vortex_id_table,
-	.probe =	vortex_probe,
-	.remove =	__devexit_p(vortex_remove),
-};
-
-static int __init vortex_init(void)
-{
-	return pci_register_driver(&vortex_driver);
-}
-
-static void __exit vortex_exit(void)
-{
-	pci_unregister_driver(&vortex_driver);
-}
-
-module_init(vortex_init);
-module_exit(vortex_exit);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 83c77c9..7c4b4d3 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -219,10 +219,24 @@
 
 int input_open_device(struct input_handle *handle)
 {
+	struct input_dev *dev = handle->dev;
+	int err;
+
+	err = down_interruptible(&dev->sem);
+	if (err)
+		return err;
+
 	handle->open++;
-	if (handle->dev->open)
-		return handle->dev->open(handle->dev);
-	return 0;
+
+	if (!dev->users++ && dev->open)
+		err = dev->open(dev);
+
+	if (err)
+		handle->open--;
+
+	up(&dev->sem);
+
+	return err;
 }
 
 int input_flush_device(struct input_handle* handle, struct file* file)
@@ -235,10 +249,17 @@
 
 void input_close_device(struct input_handle *handle)
 {
+	struct input_dev *dev = handle->dev;
+
 	input_release_device(handle);
-	if (handle->dev->close)
-		handle->dev->close(handle->dev);
+
+	down(&dev->sem);
+
+	if (!--dev->users && dev->close)
+		dev->close(dev);
 	handle->open--;
+
+	up(&dev->sem);
 }
 
 static void input_link_handle(struct input_handle *handle)
@@ -415,6 +436,8 @@
 
 	set_bit(EV_SYN, dev->evbit);
 
+	init_MUTEX(&dev->sem);
+
 	/*
 	 * If delay and period are pre-set by the driver, then autorepeating
 	 * is handled by the driver itself and we don't do it in input.c.
@@ -674,6 +697,8 @@
 	return (count > cnt) ? cnt : count;
 }
 
+static struct file_operations input_fileops;
+
 static int __init input_proc_init(void)
 {
 	struct proc_dir_entry *entry;
@@ -688,6 +713,8 @@
 		return -ENOMEM;
 	}
 	entry->owner = THIS_MODULE;
+	input_fileops = *entry->proc_fops;
+	entry->proc_fops = &input_fileops;
 	entry->proc_fops->poll = input_devices_poll;
 	entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
 	if (entry == NULL) {
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 39775fc..ff8e1bb 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -285,48 +285,33 @@
 		(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
 {
-	struct joydev_list *list = file->private_data;
-	struct joydev *joydev = list->joydev;
 	struct input_dev *dev = joydev->handle.dev;
-	void __user *argp = (void __user *)arg;
 	int i, j;
 
-	if (!joydev->exist) return -ENODEV;
-
 	switch (cmd) {
 
 		case JS_SET_CAL:
 			return copy_from_user(&joydev->glue.JS_CORR, argp,
-				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
 		case JS_GET_CAL:
 			return copy_to_user(argp, &joydev->glue.JS_CORR,
-				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
 		case JS_SET_TIMEOUT:
-			return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
+			return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
 		case JS_GET_TIMEOUT:
-			return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
-		case JS_SET_TIMELIMIT:
-			return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
-		case JS_GET_TIMELIMIT:
-			return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
-		case JS_SET_ALL:
-			return copy_from_user(&joydev->glue, argp,
-						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
-		case JS_GET_ALL:
-			return copy_to_user(argp, &joydev->glue,
-						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+			return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
 
 		case JSIOCGVERSION:
-			return put_user(JS_VERSION, (__u32 __user *) arg);
+			return put_user(JS_VERSION, (__u32 __user *) argp);
 		case JSIOCGAXES:
-			return put_user(joydev->nabs, (__u8 __user *) arg);
+			return put_user(joydev->nabs, (__u8 __user *) argp);
 		case JSIOCGBUTTONS:
-			return put_user(joydev->nkey, (__u8 __user *) arg);
+			return put_user(joydev->nkey, (__u8 __user *) argp);
 		case JSIOCSCORR:
 			if (copy_from_user(joydev->corr, argp,
-				      sizeof(struct js_corr) * joydev->nabs))
+				      sizeof(joydev->corr[0]) * joydev->nabs))
 			    return -EFAULT;
 			for (i = 0; i < joydev->nabs; i++) {
 				j = joydev->abspam[i];
@@ -335,7 +320,7 @@
 			return 0;
 		case JSIOCGCORR:
 			return copy_to_user(argp, joydev->corr,
-						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+						sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
 		case JSIOCSAXMAP:
 			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
 				return -EFAULT;
@@ -371,6 +356,84 @@
 	return -EINVAL;
 }
 
+#ifdef CONFIG_COMPAT
+static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct joydev_list *list = file->private_data;
+	struct joydev *joydev = list->joydev;
+	void __user *argp = (void __user *)arg;
+	s32 tmp32;
+	struct JS_DATA_SAVE_TYPE_32 ds32;
+	int err;
+
+	if (!joydev->exist) return -ENODEV;
+	switch(cmd) {
+	case JS_SET_TIMELIMIT:
+		err = get_user(tmp32, (s32 __user *) arg);
+		if (err == 0)
+			joydev->glue.JS_TIMELIMIT = tmp32;
+		break;
+	case JS_GET_TIMELIMIT:
+		tmp32 = joydev->glue.JS_TIMELIMIT;
+		err = put_user(tmp32, (s32 __user *) arg);
+		break;
+
+	case JS_SET_ALL:
+		err = copy_from_user(&ds32, argp,
+				     sizeof(ds32)) ? -EFAULT : 0;
+		if (err == 0) {
+			joydev->glue.JS_TIMEOUT    = ds32.JS_TIMEOUT;
+			joydev->glue.BUSY          = ds32.BUSY;
+			joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
+			joydev->glue.JS_TIMELIMIT  = ds32.JS_TIMELIMIT;
+			joydev->glue.JS_SAVE       = ds32.JS_SAVE;
+			joydev->glue.JS_CORR       = ds32.JS_CORR;
+		}
+		break;
+
+	case JS_GET_ALL:
+		ds32.JS_TIMEOUT    = joydev->glue.JS_TIMEOUT;
+		ds32.BUSY          = joydev->glue.BUSY;
+		ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
+		ds32.JS_TIMELIMIT  = joydev->glue.JS_TIMELIMIT;
+		ds32.JS_SAVE       = joydev->glue.JS_SAVE;
+		ds32.JS_CORR       = joydev->glue.JS_CORR;
+
+		err = copy_to_user(argp, &ds32,
+					  sizeof(ds32)) ? -EFAULT : 0;
+		break;
+
+	default:
+		err = joydev_ioctl_common(joydev, cmd, argp);
+	}
+	return err;
+}
+#endif /* CONFIG_COMPAT */
+
+static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct joydev_list *list = file->private_data;
+	struct joydev *joydev = list->joydev;
+	void __user *argp = (void __user *)arg;
+
+	if (!joydev->exist) return -ENODEV;
+
+	switch(cmd) {
+		case JS_SET_TIMELIMIT:
+			return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+		case JS_GET_TIMELIMIT:
+			return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+		case JS_SET_ALL:
+			return copy_from_user(&joydev->glue, argp,
+						sizeof(joydev->glue)) ? -EFAULT : 0;
+		case JS_GET_ALL:
+			return copy_to_user(argp, &joydev->glue,
+						sizeof(joydev->glue)) ? -EFAULT : 0;
+		default:
+			return joydev_ioctl_common(joydev, cmd, argp);
+	}
+}
+
 static struct file_operations joydev_fops = {
 	.owner =	THIS_MODULE,
 	.read =		joydev_read,
@@ -379,6 +442,9 @@
 	.open =		joydev_open,
 	.release =	joydev_release,
 	.ioctl =	joydev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl =	joydev_compat_ioctl,
+#endif
 	.fasync =	joydev_fasync,
 };
 
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index ad39fe4..bf34f75 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -185,7 +185,7 @@
 	a3d->reads++;
 	if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
 	    data[0] != a3d->mode || a3d_csum(data, a3d->length))
-	 	a3d->bads++;
+		a3d->bads++;
 	else
 		a3d_read(a3d, data);
 }
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 83f6daf..2659629 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -82,7 +82,7 @@
 static char adi_wmf_abs[] =	{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
 
 static short adi_wmgpe_key[] =	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,  BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
-static short adi_wmi_key[] = 	{ BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
+static short adi_wmi_key[] =	{ BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
 static short adi_wmed3d_key[] =	{ BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
 static short adi_cm2_key[] =	{ BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
 
@@ -183,7 +183,7 @@
 	int i;
 	struct adi *adi = port->adi;
 
- 	adi[0].idx = adi[1].idx = 0;
+	adi[0].idx = adi[1].idx = 0;
 
 	if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
 	if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index cf36ca9..033456b 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -51,7 +51,8 @@
 
 __obsolete_setup("amijoy=");
 
-static int amijoy_used[2] = { 0, 0 };
+static int amijoy_used;
+static DECLARE_MUTEX(amijoy_sem);
 static struct input_dev amijoy_dev[2];
 static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
 
@@ -84,26 +85,30 @@
 
 static int amijoy_open(struct input_dev *dev)
 {
-	int *used = dev->private;
+	int err;
 
-	if ((*used)++)
-		return 0;
+	err = down_interruptible(&amijoy_sem);
+	if (err)
+		return err;
 
-	if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
-		(*used)--;
+	if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
 		printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out;
 	}
 
-	return 0;
+	amijoy_used++;
+out:
+	up(&amijoy_sem);
+	return err;
 }
 
 static void amijoy_close(struct input_dev *dev)
 {
-	int *used = dev->private;
-
-	if (!--(*used))
+	down(&amijoysem);
+	if (!--amijoy_used)
 		free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+	up(&amijoy_sem);
 }
 
 static int __init amijoy_init(void)
@@ -138,8 +143,6 @@
 			amijoy_dev[i].id.product = 0x0003;
 			amijoy_dev[i].id.version = 0x0100;
 
-			amijoy_dev[i].private = amijoy_used + i;
-
 			input_register_device(amijoy_dev + i);
 			printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
 		}
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index cfdd3ac..fbd3eed 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -87,7 +87,7 @@
 #define DB9_NORMAL		0x0a
 #define DB9_NOSELECT		0x08
 
-#define DB9_MAX_DEVICES 2
+#define DB9_MAX_DEVICES		2
 
 #define DB9_GENESIS6_DELAY	14
 #define DB9_REFRESH_TIME	HZ/100
@@ -98,6 +98,7 @@
 	struct pardevice *pd;
 	int mode;
 	int used;
+	struct semaphore sem;
 	char phys[2][32];
 };
 
@@ -503,6 +504,11 @@
 {
 	struct db9 *db9 = dev->private;
 	struct parport *port = db9->pd->port;
+	int err;
+
+	err = down_interruptible(&db9->sem);
+	if (err)
+		return err;
 
 	if (!db9->used++) {
 		parport_claim(db9->pd);
@@ -514,6 +520,7 @@
 		mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
 	}
 
+	up(&db9->sem);
 	return 0;
 }
 
@@ -522,12 +529,14 @@
 	struct db9 *db9 = dev->private;
 	struct parport *port = db9->pd->port;
 
+	down(&db9->sem);
 	if (!--db9->used) {
-		del_timer(&db9->timer);
+		del_timer_sync(&db9->timer);
 		parport_write_control(port, 0x00);
 		parport_data_forward(port);
 		parport_release(db9->pd);
 	}
+	up(&db9->sem);
 }
 
 static struct db9 __init *db9_probe(int *config, int nargs)
@@ -563,12 +572,12 @@
 		}
 	}
 
-	if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
+	if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
 		parport_put_port(pp);
 		return NULL;
 	}
-	memset(db9, 0, sizeof(struct db9));
 
+	init_MUTEX(&db9->sem);
 	db9->mode = config[1];
 	init_timer(&db9->timer);
 	db9->timer.data = (long) db9;
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 8732f52..95bbdd3 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -1,12 +1,12 @@
 /*
  * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
  *
- *  Copyright (c) 1999-2004 	Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2004 		Peter Nelson <rufus-kernel@hackish.org>
+ *  Copyright (c) 1999-2004	Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2004		Peter Nelson <rufus-kernel@hackish.org>
  *
  *  Based on the work of:
- *  	Andree Borrmann		John Dahlstrom
- *  	David Kuder		Nathan Hand
+ *	Andree Borrmann		John Dahlstrom
+ *	David Kuder		Nathan Hand
  */
 
 /*
@@ -81,6 +81,7 @@
 	struct timer_list timer;
 	unsigned char pads[GC_MAX + 1];
 	int used;
+	struct semaphore sem;
 	char phys[5][32];
 };
 
@@ -433,7 +434,7 @@
 		gc_psx_read_packet(gc, data_psx, data);
 
 		for (i = 0; i < 5; i++) {
-	 		switch (data[i]) {
+			switch (data[i]) {
 
 				case GC_PSX_RUMBLE:
 
@@ -503,22 +504,33 @@
 static int gc_open(struct input_dev *dev)
 {
 	struct gc *gc = dev->private;
+	int err;
+
+	err = down_interruptible(&gc->sem);
+	if (err)
+		return err;
+
 	if (!gc->used++) {
 		parport_claim(gc->pd);
 		parport_write_control(gc->pd->port, 0x04);
 		mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
 	}
+
+	up(&gc->sem);
 	return 0;
 }
 
 static void gc_close(struct input_dev *dev)
 {
 	struct gc *gc = dev->private;
+
+	down(&gc->sem);
 	if (!--gc->used) {
-		del_timer(&gc->timer);
+		del_timer_sync(&gc->timer);
 		parport_write_control(gc->pd->port, 0x00);
 		parport_release(gc->pd);
 	}
+	up(&gc->sem);
 }
 
 static struct gc __init *gc_probe(int *config, int nargs)
@@ -542,11 +554,12 @@
 		return NULL;
 	}
 
-	if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
+	if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
 		parport_put_port(pp);
 		return NULL;
 	}
-	memset(gc, 0, sizeof(struct gc));
+
+	init_MUTEX(&gc->sem);
 
 	gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index ad13f09..7d96942 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -329,7 +329,7 @@
 
 	for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
 		gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
-	      		  gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
+			  gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
 		gf2k->dev.absmin[gf2k_abs[i]] = 32;
 		gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
 		gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 42e5005..0da7bd1 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -171,7 +171,7 @@
 	*packet = 0;
 	raw_data = gameport_read(gameport);
 	if (raw_data & 1)
- 		return IO_RETRY;
+		return IO_RETRY;
 
 	for (i = 0; i < 64; i++) {
 		raw_data = gameport_read(gameport);
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 028f351..e31b7b9 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -78,6 +78,7 @@
 	{ 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
 	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce }, //?
 	{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce }, //?
+	{ 0x06f8, 0x0004, "Gullemot Jet Leader 3D",			btn_joystick, abs_joystick, ff_iforce }, //?
 	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
 };
 
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 617c0b0..6369a24 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -229,6 +229,7 @@
 	{ USB_DEVICE(0x061c, 0xc0a4) },         /* ACT LABS Force RS */
 	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
 	{ USB_DEVICE(0x06f8, 0x0004) },		/* Guillemot Force Feedback Racing Wheel */
+	{ USB_DEVICE(0x06f8, 0xa302) },		/* Guillemot Jet Leader 3D */
 	{ }					/* Terminating entry */
 };
 
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index ec0a2a6..a436f22 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -4,8 +4,8 @@
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Based on the work of:
- *  	David Thompson
- *  	Joseph Krahn
+ *	David Thompson
+ *	Joseph Krahn
  */
 
 /*
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index 874367b..01fd2e4 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -4,7 +4,7 @@
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Based on the work of:
- *  	David Thompson
+ *	David Thompson
  */
 
 /*
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index aaee52c..9eb9954 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -79,7 +79,7 @@
 	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
 static short tmdc_btn_joy[TMDC_BTN] =
 	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
- 	  BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
+	  BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
 static short tmdc_btn_fm[TMDC_BTN] =
         { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
 static short tmdc_btn_at[TMDC_BTN] =
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index dd88b9c..28100d4 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -84,6 +84,7 @@
 	char phys[7][32];
 	int sticks;
 	int used;
+	struct semaphore sem;
 } *tgfx_base[3];
 
 /*
@@ -99,7 +100,7 @@
 	for (i = 0; i < 7; i++)
 		if (tgfx->sticks & (1 << i)) {
 
- 			dev = tgfx->dev + i;
+			dev = tgfx->dev + i;
 
 			parport_write_data(tgfx->pd->port, ~(1 << i));
 			data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
@@ -122,23 +123,34 @@
 
 static int tgfx_open(struct input_dev *dev)
 {
-        struct tgfx *tgfx = dev->private;
-        if (!tgfx->used++) {
+	struct tgfx *tgfx = dev->private;
+	int err;
+
+	err = down_interruptible(&tgfx->sem);
+	if (err)
+		return err;
+
+	if (!tgfx->used++) {
 		parport_claim(tgfx->pd);
 		parport_write_control(tgfx->pd->port, 0x04);
-                mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+		mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
 	}
-        return 0;
+
+	up(&tgfx->sem);
+	return 0;
 }
 
 static void tgfx_close(struct input_dev *dev)
 {
-        struct tgfx *tgfx = dev->private;
-        if (!--tgfx->used) {
-                del_timer(&tgfx->timer);
+	struct tgfx *tgfx = dev->private;
+
+	down(&tgfx->sem);
+	if (!--tgfx->used) {
+		del_timer_sync(&tgfx->timer);
 		parport_write_control(tgfx->pd->port, 0x00);
-        	parport_release(tgfx->pd);
+		parport_release(tgfx->pd);
 	}
+	up(&tgfx->sem);
 }
 
 /*
@@ -166,11 +178,12 @@
 		return NULL;
 	}
 
-	if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
+	if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
 		parport_put_port(pp);
 		return NULL;
 	}
-	memset(tgfx, 0, sizeof(struct tgfx));
+
+	init_MUTEX(&tgfx->sem);
 
 	tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 82fad9a..4d4985b 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -227,7 +227,7 @@
 {										\
 	return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name);		\
 }										\
-static struct device_attribute atkbd_attr_##_name = 				\
+static struct device_attribute atkbd_attr_##_name =				\
 	__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
 
 ATKBD_DEFINE_ATTR(extra);
@@ -388,7 +388,7 @@
 			value = atkbd->release ? 0 :
 				(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
 
-			switch (value) { 	/* Workaround Toshiba laptop multiple keypress */
+			switch (value) {	/* Workaround Toshiba laptop multiple keypress */
 				case 0:
 					atkbd->last = 0;
 					break;
@@ -894,7 +894,7 @@
 	if (atkbd->write) {
 		param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
 		         | (test_bit(LED_NUML,    atkbd->dev.led) ? 2 : 0)
- 		         | (test_bit(LED_CAPSL,   atkbd->dev.led) ? 4 : 0);
+		         | (test_bit(LED_CAPSL,   atkbd->dev.led) ? 4 : 0);
 
 		if (atkbd_probe(atkbd))
 			return -1;
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 0f1220a..a855171 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -39,6 +39,7 @@
 #define CORGI_KEY_CALENDER	KEY_F1
 #define CORGI_KEY_ADDRESS	KEY_F2
 #define CORGI_KEY_FN		KEY_F3
+#define CORGI_KEY_CANCEL	KEY_F4
 #define CORGI_KEY_OFF		KEY_SUSPEND
 #define CORGI_KEY_EXOK		KEY_F5
 #define CORGI_KEY_EXCANCEL	KEY_F6
@@ -46,6 +47,7 @@
 #define CORGI_KEY_EXJOGUP	KEY_F8
 #define CORGI_KEY_JAP1		KEY_LEFTCTRL
 #define CORGI_KEY_JAP2		KEY_LEFTALT
+#define CORGI_KEY_MAIL		KEY_F10
 #define CORGI_KEY_OK		KEY_F11
 #define CORGI_KEY_MENU		KEY_F12
 #define CORGI_HINGE_0		KEY_KP0
@@ -59,8 +61,8 @@
 	KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0,                                 /* 33-48 */
 	CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,         /* 49-64 */
 	CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 	  /* 65-80 */
-	KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
-	KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
+	CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
+	KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
 	CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0,   /* 113-124 */
 	CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2	  /* 125-127 */
 };
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 2694ff2..098963c 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -15,10 +15,10 @@
  * information given below, I will _not_ be liable!
  *
  * RJ10 pinout:		To DE9:		Or DB25:
- * 	1 - RxD <---->	Pin 3 (TxD) <->	Pin 2 (TxD)
- * 	2 - GND <---->	Pin 5 (GND) <->	Pin 7 (GND)
- * 	4 - TxD <---->	Pin 2 (RxD) <->	Pin 3 (RxD)
- * 	3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
+ *	1 - RxD <---->	Pin 3 (TxD) <->	Pin 2 (TxD)
+ *	2 - GND <---->	Pin 5 (GND) <->	Pin 7 (GND)
+ *	4 - TxD <---->	Pin 2 (RxD) <->	Pin 3 (RxD)
+ *	3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
  *
  * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
  * RJ10, it's like this:
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index d3e9dd6..8935290 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -42,7 +42,7 @@
 MODULE_DESCRIPTION("LoCoMo keyboard driver");
 MODULE_LICENSE("GPL");
 
-#define LOCOMOKBD_NUMKEYS 	128
+#define LOCOMOKBD_NUMKEYS	128
 
 #define KEY_ACTIVITY		KEY_F16
 #define KEY_CONTACT		KEY_F18
@@ -61,7 +61,7 @@
 	KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,				/* 90 - 99 */
 	0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A,		/* 100 - 109 */
 	KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0,		/* 110 - 119 */
-	KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 		/* 120 - 128 */
+	KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0		/* 120 - 128 */
 };
 
 #define KB_ROWS			16
@@ -82,7 +82,7 @@
 	struct locomo_dev *ldev;
 	unsigned long base;
 	spinlock_t lock;
-	
+
 	struct timer_list timer;
 };
 
@@ -95,7 +95,7 @@
 static inline void locomokbd_activate_all(unsigned long membase)
 {
 	unsigned long r;
-	
+
 	locomo_writel(0, membase + LOCOMO_KSC);
 	r = locomo_readl(membase + LOCOMO_KIC);
 	r &= 0xFEFF;
@@ -127,7 +127,7 @@
  */
 
 /* Scan the hardware keyboard and push any changes up through the input layer */
-static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs) 
+static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
 {
 	unsigned int row, col, rowd, scancode;
 	unsigned long flags;
@@ -138,7 +138,7 @@
 
 	if (regs)
 		input_regs(&locomokbd->input, regs);
-	
+
 	locomokbd_charge_all(membase);
 
 	num_pressed = 0;
@@ -146,9 +146,9 @@
 
 		locomokbd_activate_col(membase, col);
 		udelay(KB_DELAY);
-		 
+
 		rowd = ~locomo_readl(membase + LOCOMO_KIB);
-		for (row = 0; row < KB_ROWS; row++ ) {
+		for (row = 0; row < KB_ROWS; row++) {
 			scancode = SCANCODE(col, row);
 			if (rowd & KB_ROWMASK(row)) {
 				num_pressed += 1;
@@ -170,7 +170,7 @@
 	spin_unlock_irqrestore(&locomokbd->lock, flags);
 }
 
-/* 
+/*
  * LoCoMo keyboard interrupt handler.
  */
 static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -205,8 +205,8 @@
 	memset(locomokbd, 0, sizeof(struct locomokbd));
 
 	/* try and claim memory region */
-	if (!request_mem_region((unsigned long) dev->mapbase, 
-				dev->length, 
+	if (!request_mem_region((unsigned long) dev->mapbase,
+				dev->length,
 				LOCOMO_DRIVER_NAME(dev))) {
 		ret = -EBUSY;
 		printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
@@ -225,7 +225,7 @@
 	locomokbd->timer.data = (unsigned long) locomokbd;
 
 	locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
-	
+
 	init_input_dev(&locomokbd->input);
 	locomokbd->input.keycode = locomokbd->keycode;
 	locomokbd->input.keycodesize = sizeof(unsigned char);
@@ -271,11 +271,11 @@
 static int locomokbd_remove(struct locomo_dev *dev)
 {
 	struct locomokbd *locomokbd = locomo_get_drvdata(dev);
-	
+
 	free_irq(dev->irq[0], locomokbd);
 
 	del_timer_sync(&locomokbd->timer);
-	
+
 	input_unregister_device(&locomokbd->input);
 	locomo_set_drvdata(dev, NULL);
 
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
index 859ed77..eecbde2 100644
--- a/drivers/input/keyboard/maple_keyb.c
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -1,6 +1,6 @@
 /*
  *	$Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
- * 	SEGA Dreamcast keyboard driver
+ *	SEGA Dreamcast keyboard driver
  *	Based on drivers/usb/usbkbd.c
  */
 
@@ -40,7 +40,6 @@
 	struct input_dev dev;
 	unsigned char new[8];
 	unsigned char old[8];
-	int open;
 };
 
 
@@ -95,22 +94,6 @@
 	}
 }
 
-
-static int dc_kbd_open(struct input_dev *dev)
-{
-	struct dc_kbd *kbd = dev->private;
-	kbd->open++;
-	return 0;
-}
-
-
-static void dc_kbd_close(struct input_dev *dev)
-{
-	struct dc_kbd *kbd = dev->private;
-	kbd->open--;
-}
-
-
 static int dc_kbd_connect(struct maple_device *dev)
 {
 	int i;
@@ -133,9 +116,6 @@
 	clear_bit(0, kbd->dev.keybit);
 
 	kbd->dev.private = kbd;
-	kbd->dev.open = dc_kbd_open;
-	kbd->dev.close = dc_kbd_close;
-	kbd->dev.event = NULL;
 
 	kbd->dev.name = dev->product_name;
 	kbd->dev.id.bustype = BUS_MAPLE;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 158c8e8..9871099 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -298,9 +298,11 @@
 	/* check if absmin/absmax/absfuzz/absflat are filled as
 	 * told in Documentation/input/input-programming.txt */
 	if (test_bit(EV_ABS, dev->evbit)) {
-		retval = uinput_validate_absbits(dev);
-		if (retval < 0)
+		int err = uinput_validate_absbits(dev);
+		if (err < 0) {
+			retval = err;
 			kfree(dev->name);
+		}
 	}
 
 exit:
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index a786419..c4909b4 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -15,4 +15,4 @@
 obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 
-psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o
+psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7bf4be7..a12e981 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -30,10 +30,11 @@
 
 #define ALPS_DUALPOINT	0x01
 #define ALPS_WHEEL	0x02
-#define ALPS_FW_BK	0x04
+#define ALPS_FW_BK_1	0x04
 #define ALPS_4BTN	0x08
 #define ALPS_OLDPROTO	0x10
 #define ALPS_PASS	0x20
+#define ALPS_FW_BK_2	0x40
 
 static struct alps_model_info alps_model_data[] = {
 	{ { 0x33, 0x02, 0x0a },	0x88, 0xf8, ALPS_OLDPROTO },		/* UMAX-530T */
@@ -43,11 +44,11 @@
 	{ { 0x63, 0x02, 0x14 },	0xf8, 0xf8, 0 },
 	{ { 0x63, 0x02, 0x28 },	0xf8, 0xf8, 0 },
 	{ { 0x63, 0x02, 0x3c },	0x8f, 0x8f, ALPS_WHEEL },		/* Toshiba Satellite S2400-103 */
-	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK },		/* NEC Versa L320 */
+	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK_1 },		/* NEC Versa L320 */
 	{ { 0x63, 0x02, 0x64 },	0xf8, 0xf8, 0 },
 	{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS },		/* Dell Latitude D800 */
 	{ { 0x73, 0x02, 0x0a },	0xf8, 0xf8, 0 },
-	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, 0 },
+	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, ALPS_FW_BK_2 },		/* Ahtec Laptop */
 	{ { 0x20, 0x02, 0x0e },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
 	{ { 0x22, 0x02, 0x0a },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
 	{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
@@ -61,11 +62,11 @@
 
 /*
  * ALPS abolute Mode - new format
- * 
- * byte 0:  1    ?    ?    ?    1    ?    ?    ? 
+ *
+ * byte 0:  1    ?    ?    ?    1    ?    ?    ?
  * byte 1:  0   x6   x5   x4   x3   x2   x1   x0
  * byte 2:  0   x10  x9   x8   x7    ?  fin  ges
- * byte 3:  0   y9   y8   y7    1    M    R    L 
+ * byte 3:  0   y9   y8   y7    1    M    R    L
  * byte 4:  0   y6   y5   y4   y3   y2   y1   y0
  * byte 5:  0   z6   z5   z4   z3   z2   z1   z0
  *
@@ -81,11 +82,12 @@
 	struct input_dev *dev = &psmouse->dev;
 	struct input_dev *dev2 = &priv->dev2;
 	int x, y, z, ges, fin, left, right, middle;
+	int back = 0, forward = 0;
 
 	input_regs(dev, regs);
 
 	if ((packet[0] & 0xc8) == 0x08) {   /* 3-byte PS/2 packet */
-		input_report_key(dev2, BTN_LEFT,   packet[0] & 1);    
+		input_report_key(dev2, BTN_LEFT,   packet[0] & 1);
 		input_report_key(dev2, BTN_RIGHT,  packet[0] & 2);
 		input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
 		input_report_rel(dev2, REL_X,
@@ -112,6 +114,18 @@
 		z = packet[5];
 	}
 
+	if (priv->i->flags & ALPS_FW_BK_1) {
+		back = packet[2] & 4;
+		forward = packet[0] & 0x10;
+	}
+
+	if (priv->i->flags & ALPS_FW_BK_2) {
+		back = packet[3] & 4;
+		forward = packet[2] & 4;
+		if ((middle = forward && back))
+			forward = back = 0;
+	}
+
 	ges = packet[2] & 1;
 	fin = packet[2] & 2;
 
@@ -155,13 +169,12 @@
 	input_report_abs(dev, ABS_PRESSURE, z);
 	input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 
-
 	if (priv->i->flags & ALPS_WHEEL)
 		input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
 
-	if (priv->i->flags & ALPS_FW_BK) {
-		input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
-		input_report_key(dev, BTN_BACK, packet[2] & 0x04);
+	if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+		input_report_key(dev, BTN_FORWARD, forward);
+		input_report_key(dev, BTN_BACK, back);
 	}
 
 	input_sync(dev);
@@ -257,7 +270,6 @@
 static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[3];
 	int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
 
 	if (ps2_command(ps2dev, NULL, cmd) ||
@@ -267,7 +279,7 @@
 		return -1;
 
 	/* we may get 3 more bytes, just ignore them */
-	ps2_command(ps2dev, param, 0x0300);
+	ps2_drain(ps2dev, 3, 100);
 
 	return 0;
 }
@@ -425,7 +437,7 @@
 		psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
 	}
 
-	if (priv->i->flags & ALPS_FW_BK) {
+	if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
 		psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
 		psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
 	}
@@ -436,8 +448,8 @@
 	priv->dev2.id.bustype = BUS_I8042;
 	priv->dev2.id.vendor = 0x0002;
 	priv->dev2.id.product = PSMOUSE_ALPS;
-	priv->dev2.id.version = 0x0000; 
-	
+	priv->dev2.id.version = 0x0000;
+
 	priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
 	priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
@@ -461,17 +473,15 @@
 int alps_detect(struct psmouse *psmouse, int set_properties)
 {
 	int version;
-	struct alps_model_info *model; 
+	struct alps_model_info *model;
 
 	if (!(model = alps_get_model(psmouse, &version)))
 		return -1;
 
 	if (set_properties) {
 		psmouse->vendor = "ALPS";
-		if (model->flags & ALPS_DUALPOINT) 
-			psmouse->name = "DualPoint TouchPad";
-		else
-			psmouse->name = "GlidePoint";
+		psmouse->name = model->flags & ALPS_DUALPOINT ?
+				"DualPoint TouchPad" : "GlidePoint";
 		psmouse->model = version;
 	}
 	return 0;
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index 7baa09c..e994849 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -33,7 +33,6 @@
 MODULE_DESCRIPTION("Amiga mouse driver");
 MODULE_LICENSE("GPL");
 
-static int amimouse_used = 0;
 static int amimouse_lastx, amimouse_lasty;
 static struct input_dev amimouse_dev;
 
@@ -81,16 +80,12 @@
 {
 	unsigned short joy0dat;
 
-        if (amimouse_used++)
-                return 0;
-
 	joy0dat = custom.joy0dat;
 
 	amimouse_lastx = joy0dat & 0xff;
 	amimouse_lasty = joy0dat >> 8;
 
 	if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
-                amimouse_used--;
                 printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
                 return -EBUSY;
         }
@@ -100,8 +95,7 @@
 
 static void amimouse_close(struct input_dev *dev)
 {
-        if (!--amimouse_used)
-		free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+	free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
 }
 
 static int __init amimouse_init(void)
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index ca4e968..1f62c01 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -17,18 +17,18 @@
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -87,29 +87,23 @@
 
 __obsolete_setup("inport_irq=");
 
-static int inport_used;
-
 static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 static int inport_open(struct input_dev *dev)
 {
-	if (!inport_used++) {
-		if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
-			return -EBUSY;
-		outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
-		outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
-	}
+	if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
+		return -EBUSY;
+	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+	outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
 
 	return 0;
 }
 
 static void inport_close(struct input_dev *dev)
 {
-	if (!--inport_used) {
-		outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
-		outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
-		free_irq(inport_irq, NULL);
-	}
+	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+	outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+	free_irq(inport_irq, NULL);
 }
 
 static struct input_dev inport_dev = {
@@ -120,11 +114,11 @@
 	.close	= inport_close,
 	.name	= INPORT_NAME,
 	.phys	= "isa023c/input0",
-	.id = { 
- 		.bustype = BUS_ISA,
-        	.vendor  = INPORT_VENDOR,
-        	.product = 0x0001,
-        	.version = 0x0100,
+	.id = {
+		.bustype = BUS_ISA,
+		.vendor  = INPORT_VENDOR,
+		.product = 0x0001,
+		.version = 0x0100,
 	},
 };
 
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
new file mode 100644
index 0000000..bd9df9b
--- /dev/null
+++ b/drivers/input/mouse/lifebook.c
@@ -0,0 +1,134 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
+ *
+ * TouchScreen detection, absolute mode setting and packet layout is taken from
+ * Harald Hoyer's description of the device.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/dmi.h>
+
+#include "psmouse.h"
+#include "lifebook.h"
+
+static struct dmi_system_id lifebook_dmi_table[] = {
+       {
+               .ident = "Lifebook B",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
+               },
+       },
+       { }
+};
+
+
+static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	unsigned char *packet = psmouse->packet;
+	struct input_dev *dev = &psmouse->dev;
+
+	if (psmouse->pktcnt != 3)
+		return PSMOUSE_GOOD_DATA;
+
+	input_regs(dev, regs);
+
+	/* calculate X and Y */
+	if ((packet[0] & 0x08) == 0x00) {
+		input_report_abs(dev, ABS_X,
+				 (packet[1] | ((packet[0] & 0x30) << 4)));
+		input_report_abs(dev, ABS_Y,
+				 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
+	} else {
+		input_report_rel(dev, REL_X,
+				((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
+		input_report_rel(dev, REL_Y,
+				 -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
+	}
+
+	input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+	input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
+
+	input_sync(dev);
+
+	return PSMOUSE_FULL_PACKET;
+}
+
+static int lifebook_absolute_mode(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	unsigned char param;
+
+	if (psmouse_reset(psmouse))
+		return -1;
+
+	/*
+	   Enable absolute output -- ps2_command fails always but if
+	   you leave this call out the touchsreen will never send
+	   absolute coordinates
+	*/
+	param = 0x07;
+	ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
+
+	return 0;
+}
+
+static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+	unsigned char params[] = { 0, 1, 2, 2, 3 };
+
+	if (resolution == 0 || resolution > 400)
+		resolution = 400;
+
+	ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES);
+	psmouse->resolution = 50 << params[resolution / 100];
+}
+
+static void lifebook_disconnect(struct psmouse *psmouse)
+{
+	psmouse_reset(psmouse);
+}
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties)
+{
+        if (!dmi_check_system(lifebook_dmi_table))
+                return -1;
+
+	if (set_properties) {
+		psmouse->vendor = "Fujitsu";
+		psmouse->name = "Lifebook TouchScreen";
+	}
+
+        return 0;
+}
+
+int lifebook_init(struct psmouse *psmouse)
+{
+	if (lifebook_absolute_mode(psmouse))
+		return -1;
+
+	psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
+	psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+	psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0);
+	input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0);
+
+	psmouse->protocol_handler = lifebook_process_byte;
+	psmouse->set_resolution = lifebook_set_resolution;
+	psmouse->disconnect = lifebook_disconnect;
+	psmouse->reconnect  = lifebook_absolute_mode;
+	psmouse->pktsize = 3;
+
+	return 0;
+}
+
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
new file mode 100644
index 0000000..be1c094
--- /dev/null
+++ b/drivers/input/mouse/lifebook.h
@@ -0,0 +1,17 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _LIFEBOOK_H
+#define _LIFEBOOK_H
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties);
+int lifebook_init(struct psmouse *psmouse);
+
+#endif
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index 77eb83e..8b52431 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -18,18 +18,18 @@
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -77,16 +77,11 @@
 
 __obsolete_setup("logibm_irq=");
 
-static int logibm_used = 0;
-
 static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 static int logibm_open(struct input_dev *dev)
 {
-	if (logibm_used++)
-		return 0;
 	if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
-		logibm_used--;
 		printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
 		return -EBUSY;
 	}
@@ -96,8 +91,6 @@
 
 static void logibm_close(struct input_dev *dev)
 {
-	if (--logibm_used)
-		return;
 	outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
 	free_irq(logibm_irq, NULL);
 }
@@ -167,7 +160,7 @@
 	outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
 
 	input_register_device(&logibm_dev);
-	
+
 	printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
 
 	return 0;
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
index 12dc0ef..e90c60c 100644
--- a/drivers/input/mouse/maplemouse.c
+++ b/drivers/input/mouse/maplemouse.c
@@ -1,6 +1,6 @@
 /*
  *	$Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
- * 	SEGA Dreamcast mouse driver
+ *	SEGA Dreamcast mouse driver
  *	Based on drivers/usb/usbmouse.c
  */
 
@@ -15,80 +15,51 @@
 MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
 MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
 
-struct dc_mouse {
-	struct input_dev dev;
-	int open;
-};
-
-
 static void dc_mouse_callback(struct mapleq *mq)
 {
 	int buttons, relx, rely, relz;
 	struct maple_device *mapledev = mq->dev;
-	struct dc_mouse *mouse = mapledev->private_data;
-	struct input_dev *dev = &mouse->dev;
+	struct input_dev *dev = mapledev->private_data;
 	unsigned char *res = mq->recvbuf;
 
 	buttons = ~res[8];
-	relx=*(unsigned short *)(res+12)-512;
-	rely=*(unsigned short *)(res+14)-512;
-	relz=*(unsigned short *)(res+16)-512;
+	relx = *(unsigned short *)(res + 12) - 512;
+	rely = *(unsigned short *)(res + 14) - 512;
+	relz = *(unsigned short *)(res + 16) - 512;
 
-	input_report_key(dev, BTN_LEFT,   buttons&4);
-	input_report_key(dev, BTN_MIDDLE, buttons&9);
-	input_report_key(dev, BTN_RIGHT,  buttons&2);
+	input_report_key(dev, BTN_LEFT,   buttons & 4);
+	input_report_key(dev, BTN_MIDDLE, buttons & 9);
+	input_report_key(dev, BTN_RIGHT,  buttons & 2);
 	input_report_rel(dev, REL_X,      relx);
 	input_report_rel(dev, REL_Y,      rely);
 	input_report_rel(dev, REL_WHEEL,  relz);
 	input_sync(dev);
 }
 
-
-static int dc_mouse_open(struct input_dev *dev)
-{
-	struct dc_mouse *mouse = dev->private;
-	mouse->open++;
-	return 0;
-}
-
-
-static void dc_mouse_close(struct input_dev *dev)
-{
-	struct dc_mouse *mouse = dev->private;
-	mouse->open--;
-}
-
-
 static int dc_mouse_connect(struct maple_device *dev)
 {
 	unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
-	struct dc_mouse *mouse;
+	struct input_dev *input_dev;
 
-	if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
+	if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL)))
 		return -1;
-	memset(mouse, 0, sizeof(struct dc_mouse));
 
-	dev->private_data = mouse;
+	dev->private_data = input_dev;
 
-	mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-	mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-	mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+	memset(input_dev, 0, sizeof(struct dc_mouse));
+	init_input_dev(input_dev);
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
 
-	init_input_dev(&mouse->dev);
+	input_dev->name = dev->product_name;
+	input_dev->id.bustype = BUS_MAPLE;
 
-	mouse->dev.private = mouse;
-	mouse->dev.open = dc_mouse_open;
-	mouse->dev.close = dc_mouse_close;
-	mouse->dev.event = NULL;
-
-	mouse->dev.name = dev->product_name;
-	mouse->dev.id.bustype = BUS_MAPLE;
-	
-	input_register_device(&mouse->dev);
+	input_register_device(input_dev);
 
 	maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
 
-	printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
+	printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name);
 
 	return 0;
 }
@@ -96,10 +67,10 @@
 
 static void dc_mouse_disconnect(struct maple_device *dev)
 {
-	struct dc_mouse *mouse = dev->private_data;
+	struct input_dev *input_dev = dev->private_data;
 
-	input_unregister_device(&mouse->dev);
-	kfree(mouse);
+	input_unregister_device(input_dev);
+	kfree(input_dev);
 }
 
 
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index 0c74918..93393d5 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -4,7 +4,7 @@
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
  *  Based on the work of:
- *	Alan Cox	Robin O'Leary	
+ *	Alan Cox	Robin O'Leary
  */
 
 /*
@@ -56,7 +56,6 @@
 static struct input_dev pc110pad_dev;
 static int pc110pad_data[3];
 static int pc110pad_count;
-static int pc110pad_used;
 
 static char *pc110pad_name = "IBM PC110 TouchPad";
 static char *pc110pad_phys = "isa15e0/input0";
@@ -74,7 +73,7 @@
 
 	if (pc110pad_count < 3)
 		return IRQ_HANDLED;
-	
+
 	input_regs(&pc110pad_dev, regs);
 	input_report_key(&pc110pad_dev, BTN_TOUCH,
 		pc110pad_data[0] & 0x01);
@@ -90,15 +89,11 @@
 
 static void pc110pad_close(struct input_dev *dev)
 {
-	if (!--pc110pad_used)
-		outb(PC110PAD_OFF, pc110pad_io + 2);
+	outb(PC110PAD_OFF, pc110pad_io + 2);
 }
 
 static int pc110pad_open(struct input_dev *dev)
 {
-	if (pc110pad_used++)
-		return 0;
-
 	pc110pad_interrupt(0,NULL,NULL);
 	pc110pad_interrupt(0,NULL,NULL);
 	pc110pad_interrupt(0,NULL,NULL);
@@ -145,7 +140,7 @@
 
 	pc110pad_dev.absmax[ABS_X] = 0x1ff;
 	pc110pad_dev.absmax[ABS_Y] = 0x0ff;
-        
+
 	pc110pad_dev.open = pc110pad_open;
         pc110pad_dev.close = pc110pad_close;
 
@@ -156,17 +151,17 @@
 	pc110pad_dev.id.product = 0x0001;
 	pc110pad_dev.id.version = 0x0100;
 
-	input_register_device(&pc110pad_dev);	
+	input_register_device(&pc110pad_dev);
 
 	printk(KERN_INFO "input: %s at %#x irq %d\n",
 		pc110pad_name, pc110pad_io, pc110pad_irq);
-	
+
 	return 0;
 }
- 
+
 static void __exit pc110pad_exit(void)
 {
-	input_unregister_device(&pc110pad_dev);	
+	input_unregister_device(&pc110pad_dev);
 
 	outb(PC110PAD_OFF, pc110pad_io + 2);
 
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 019034b..19785a6c 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -24,6 +24,7 @@
 #include "synaptics.h"
 #include "logips2pp.h"
 #include "alps.h"
+#include "lifebook.h"
 
 #define DRIVER_DESC	"PS/2 mouse driver"
 
@@ -31,10 +32,9 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static unsigned int psmouse_max_proto = -1U;
+static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
 static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
 static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
-static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
 #define param_check_proto_abbrev(name, p)	__param_check(name, p, unsigned int)
 #define param_set_proto_abbrev			psmouse_set_maxproto
 #define param_get_proto_abbrev			psmouse_get_maxproto
@@ -57,6 +57,7 @@
 module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
+PSMOUSE_DEFINE_ATTR(protocol);
 PSMOUSE_DEFINE_ATTR(rate);
 PSMOUSE_DEFINE_ATTR(resolution);
 PSMOUSE_DEFINE_ATTR(resetafter);
@@ -67,7 +68,23 @@
 __obsolete_setup("psmouse_resetafter=");
 __obsolete_setup("psmouse_rate=");
 
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
+/*
+ * psmouse_sem protects all operations changing state of mouse
+ * (connecting, disconnecting, changing rate or resolution via
+ * sysfs). We could use a per-device semaphore but since there
+ * rarely more than one PS/2 mouse connected and since semaphore
+ * is taken in "slow" paths it is not worth it.
+ */
+static DECLARE_MUTEX(psmouse_sem);
+
+struct psmouse_protocol {
+	enum psmouse_type type;
+	char *name;
+	char *alias;
+	int maxproto;
+	int (*detect)(struct psmouse *, int);
+	int (*init)(struct psmouse *);
+};
 
 /*
  * psmouse_process_byte() analyzes the PS/2 data stream and reports
@@ -407,12 +424,15 @@
  */
 static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
 {
-	if (!psmouse->vendor) psmouse->vendor = "Generic";
-	if (!psmouse->name) psmouse->name = "Mouse";
+	if (set_properties) {
+		if (!psmouse->vendor) psmouse->vendor = "Generic";
+		if (!psmouse->name) psmouse->name = "Mouse";
+	}
 
 	return 0;
 }
 
+
 /*
  * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
  * the mouse may have.
@@ -424,6 +444,17 @@
 	int synaptics_hardware = 0;
 
 /*
+ * We always check for lifebook because it does not disturb mouse
+ * (it only checks DMI information).
+ */
+	if (lifebook_detect(psmouse, set_properties) == 0) {
+		if (max_proto > PSMOUSE_IMEX) {
+			if (!set_properties || lifebook_init(psmouse) == 0)
+				return PSMOUSE_LIFEBOOK;
+		}
+	}
+
+/*
  * Try Kensington ThinkingMouse (we try first, because synaptics probe
  * upsets the thinkingmouse).
  */
@@ -506,6 +537,103 @@
 	return PSMOUSE_PS2;
 }
 
+static struct psmouse_protocol psmouse_protocols[] = {
+	{
+		.type		= PSMOUSE_PS2,
+		.name		= "PS/2",
+		.alias		= "bare",
+		.maxproto	= 1,
+		.detect		= ps2bare_detect,
+	},
+	{
+		.type		= PSMOUSE_PS2PP,
+		.name		= "PS2++",
+		.alias		= "logitech",
+		.detect		= ps2pp_init,
+	},
+	{
+		.type		= PSMOUSE_THINKPS,
+		.name		= "ThinkPS/2",
+		.alias		= "thinkps",
+		.detect		= thinking_detect,
+	},
+	{
+		.type		= PSMOUSE_GENPS,
+		.name		= "GenPS/2",
+		.alias		= "genius",
+		.detect		= genius_detect,
+	},
+	{
+		.type		= PSMOUSE_IMPS,
+		.name		= "ImPS/2",
+		.alias		= "imps",
+		.maxproto	= 1,
+		.detect		= intellimouse_detect,
+	},
+	{
+		.type		= PSMOUSE_IMEX,
+		.name		= "ImExPS/2",
+		.alias		= "exps",
+		.maxproto	= 1,
+		.detect		= im_explorer_detect,
+	},
+	{
+		.type		= PSMOUSE_SYNAPTICS,
+		.name		= "SynPS/2",
+		.alias		= "synaptics",
+		.detect		= synaptics_detect,
+		.init		= synaptics_init,
+	},
+	{
+		.type		= PSMOUSE_ALPS,
+		.name		= "AlpsPS/2",
+		.alias		= "alps",
+		.detect		= alps_detect,
+		.init		= alps_init,
+	},
+	{
+		.type		= PSMOUSE_LIFEBOOK,
+		.name		= "LBPS/2",
+		.alias		= "lifebook",
+		.init		= lifebook_init,
+	},
+	{
+		.type		= PSMOUSE_AUTO,
+		.name		= "auto",
+		.alias		= "any",
+		.maxproto	= 1,
+	},
+};
+
+static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++)
+		if (psmouse_protocols[i].type == type)
+			return &psmouse_protocols[i];
+
+	WARN_ON(1);
+	return &psmouse_protocols[0];
+}
+
+static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
+{
+	struct psmouse_protocol *p;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
+		p = &psmouse_protocols[i];
+
+		if ((strlen(p->name) == len && !strncmp(p->name, name, len)) ||
+		    (strlen(p->alias) == len && !strncmp(p->alias, name, len)))
+			return &psmouse_protocols[i];
+	}
+
+	return NULL;
+}
+
+
 /*
  * psmouse_probe() probes for a PS/2 mouse.
  */
@@ -653,30 +781,84 @@
 
 static void psmouse_disconnect(struct serio *serio)
 {
-	struct psmouse *psmouse, *parent;
+	struct psmouse *psmouse, *parent = NULL;
 
+	psmouse = serio_get_drvdata(serio);
+
+	device_remove_file(&serio->dev, &psmouse_attr_protocol);
 	device_remove_file(&serio->dev, &psmouse_attr_rate);
 	device_remove_file(&serio->dev, &psmouse_attr_resolution);
 	device_remove_file(&serio->dev, &psmouse_attr_resetafter);
 
-	psmouse = serio_get_drvdata(serio);
+	down(&psmouse_sem);
+
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 		parent = serio_get_drvdata(serio->parent);
-		if (parent->pt_deactivate)
-			parent->pt_deactivate(parent);
+		psmouse_deactivate(parent);
 	}
 
 	if (psmouse->disconnect)
 		psmouse->disconnect(psmouse);
 
+	if (parent && parent->pt_deactivate)
+		parent->pt_deactivate(parent);
+
 	psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 
 	input_unregister_device(&psmouse->dev);
 	serio_close(serio);
 	serio_set_drvdata(serio, NULL);
 	kfree(psmouse);
+
+	if (parent)
+		psmouse_activate(parent);
+
+	up(&psmouse_sem);
+}
+
+static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
+{
+	memset(&psmouse->dev, 0, sizeof(struct input_dev));
+
+	init_input_dev(&psmouse->dev);
+
+	psmouse->dev.private = psmouse;
+	psmouse->dev.dev = &psmouse->ps2dev.serio->dev;
+
+	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+	psmouse->set_rate = psmouse_set_rate;
+	psmouse->set_resolution = psmouse_set_resolution;
+	psmouse->protocol_handler = psmouse_process_byte;
+	psmouse->pktsize = 3;
+
+	if (proto && (proto->detect || proto->init)) {
+		if (proto->detect && proto->detect(psmouse, 1) < 0)
+			return -1;
+
+		if (proto->init && proto->init(psmouse) < 0)
+			return -1;
+
+		psmouse->type = proto->type;
+	}
+	else
+		psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+
+	sprintf(psmouse->devname, "%s %s %s",
+		psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+
+	psmouse->dev.name = psmouse->devname;
+	psmouse->dev.phys = psmouse->phys;
+	psmouse->dev.id.bustype = BUS_I8042;
+	psmouse->dev.id.vendor = 0x0002;
+	psmouse->dev.id.product = psmouse->type;
+	psmouse->dev.id.version = psmouse->model;
+
+	return 0;
 }
 
 /*
@@ -688,6 +870,8 @@
 	struct psmouse *psmouse, *parent = NULL;
 	int retval;
 
+	down(&psmouse_sem);
+
 	/*
 	 * If this is a pass-through port deactivate parent so the device
 	 * connected to this port can be successfully identified
@@ -697,20 +881,14 @@
 		psmouse_deactivate(parent);
 	}
 
-	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
+	if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
 		retval = -ENOMEM;
 		goto out;
 	}
 
-	memset(psmouse, 0, sizeof(struct psmouse));
-
 	ps2_init(&psmouse->ps2dev, serio);
 	sprintf(psmouse->phys, "%s/input0", serio->phys);
-	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
-	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
-	psmouse->dev.private = psmouse;
-	psmouse->dev.dev = &serio->dev;
+
 	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
 	serio_set_drvdata(serio, psmouse);
@@ -734,25 +912,10 @@
 	psmouse->resolution = psmouse_resolution;
 	psmouse->resetafter = psmouse_resetafter;
 	psmouse->smartscroll = psmouse_smartscroll;
-	psmouse->set_rate = psmouse_set_rate;
-	psmouse->set_resolution = psmouse_set_resolution;
-	psmouse->protocol_handler = psmouse_process_byte;
-	psmouse->pktsize = 3;
 
-	psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
-
-	sprintf(psmouse->devname, "%s %s %s",
-		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
-
-	psmouse->dev.name = psmouse->devname;
-	psmouse->dev.phys = psmouse->phys;
-	psmouse->dev.id.bustype = BUS_I8042;
-	psmouse->dev.id.vendor = 0x0002;
-	psmouse->dev.id.product = psmouse->type;
-	psmouse->dev.id.version = psmouse->model;
+	psmouse_switch_protocol(psmouse, NULL);
 
 	input_register_device(&psmouse->dev);
-
 	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
@@ -762,6 +925,7 @@
 	if (parent && parent->pt_activate)
 		parent->pt_activate(parent);
 
+	device_create_file(&serio->dev, &psmouse_attr_protocol);
 	device_create_file(&serio->dev, &psmouse_attr_rate);
 	device_create_file(&serio->dev, &psmouse_attr_resolution);
 	device_create_file(&serio->dev, &psmouse_attr_resetafter);
@@ -771,10 +935,11 @@
 	retval = 0;
 
 out:
-	/* If this is a pass-through port the parent awaits to be activated */
+	/* If this is a pass-through port the parent needs to be re-activated */
 	if (parent)
 		psmouse_activate(parent);
 
+	up(&psmouse_sem);
 	return retval;
 }
 
@@ -791,6 +956,8 @@
 		return -1;
 	}
 
+	down(&psmouse_sem);
+
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
@@ -823,6 +990,7 @@
 	if (parent)
 		psmouse_activate(parent);
 
+	up(&psmouse_sem);
 	return rc;
 }
 
@@ -893,26 +1061,109 @@
 
 	if (serio->drv != &psmouse_drv) {
 		retval = -ENODEV;
-		goto out;
+		goto out_unpin;
+	}
+
+	retval = down_interruptible(&psmouse_sem);
+	if (retval)
+		goto out_unpin;
+
+	if (psmouse->state == PSMOUSE_IGNORE) {
+		retval = -ENODEV;
+		goto out_up;
 	}
 
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
 	}
+
 	psmouse_deactivate(psmouse);
 
 	retval = handler(psmouse, buf, count);
 
-	psmouse_activate(psmouse);
+	if (retval != -ENODEV)
+		psmouse_activate(psmouse);
+
 	if (parent)
 		psmouse_activate(parent);
 
-out:
+ out_up:
+	up(&psmouse_sem);
+ out_unpin:
 	serio_unpin_driver(serio);
 	return retval;
 }
 
+static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf)
+{
+	return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
+}
+
+static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count)
+{
+	struct serio *serio = psmouse->ps2dev.serio;
+	struct psmouse *parent = NULL;
+	struct psmouse_protocol *proto;
+	int retry = 0;
+
+	if (!(proto = psmouse_protocol_by_name(buf, count)))
+		return -EINVAL;
+
+	if (psmouse->type == proto->type)
+		return count;
+
+	while (serio->child) {
+		if (++retry > 3) {
+			printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
+			return -EIO;
+		}
+
+		up(&psmouse_sem);
+		serio_unpin_driver(serio);
+		serio_unregister_child_port(serio);
+		serio_pin_driver_uninterruptible(serio);
+		down(&psmouse_sem);
+
+		if (serio->drv != &psmouse_drv)
+			return -ENODEV;
+
+		if (psmouse->type == proto->type)
+			return count; /* switched by other thread */
+	}
+
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
+		if (parent->pt_deactivate)
+			parent->pt_deactivate(parent);
+	}
+
+	if (psmouse->disconnect)
+		psmouse->disconnect(psmouse);
+
+	psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+	input_unregister_device(&psmouse->dev);
+
+	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+	if (psmouse_switch_protocol(psmouse, proto) < 0) {
+		psmouse_reset(psmouse);
+		/* default to PSMOUSE_PS2 */
+		psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);
+	}
+
+	psmouse_initialize(psmouse);
+	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+	input_register_device(&psmouse->dev);
+	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
+
+	if (parent && parent->pt_activate)
+		parent->pt_activate(parent);
+
+	return count;
+}
+
 static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
 {
 	return sprintf(buf, "%d\n", psmouse->rate);
@@ -969,34 +1220,26 @@
 
 static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
 {
-	int i;
+	struct psmouse_protocol *proto;
 
 	if (!val)
 		return -EINVAL;
 
-	if (!strncmp(val, "any", 3)) {
-		*((unsigned int *)kp->arg) = -1U;
-		return 0;
-	}
+	proto = psmouse_protocol_by_name(val, strlen(val));
 
-	for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
-		if (!psmouse_proto_abbrev[i])
-			continue;
+	if (!proto || !proto->maxproto)
+		return -EINVAL;
 
-		if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
-			*((unsigned int *)kp->arg) = i;
-			return 0;
-		}
-	}
+	*((unsigned int *)kp->arg) = proto->type;
 
-	return -EINVAL;					\
+	return 0;					\
 }
 
 static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
 {
-	return sprintf(buffer, "%s\n",
-			psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
-				psmouse_proto_abbrev[psmouse_max_proto] : "any");
+	int type = *((unsigned int *)kp->arg);
+
+	return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
 }
 
 static int __init psmouse_init(void)
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 79e17a0..86691cf 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -77,6 +77,8 @@
 	PSMOUSE_IMEX,
 	PSMOUSE_SYNAPTICS,
 	PSMOUSE_ALPS,
+	PSMOUSE_LIFEBOOK,
+	PSMOUSE_AUTO		/* This one should always be last */
 };
 
 int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
@@ -99,7 +101,7 @@
 {										\
 	return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name);	\
 }										\
-static struct device_attribute psmouse_attr_##_name = 				\
+static struct device_attribute psmouse_attr_##_name =				\
 	__ATTR(_name, S_IWUSR | S_IRUGO,					\
 		psmouse_do_show_##_name, psmouse_do_set_##_name);
 
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 7280f68..8fe1212 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -59,7 +59,7 @@
 	b = (short) (__raw_readl(0xe0310000) ^ 0x70);
 
 	dx = x - rpcmouse_lastx;
-	dy = y - rpcmouse_lasty; 
+	dy = y - rpcmouse_lasty;
 
 	rpcmouse_lastx = x;
 	rpcmouse_lasty = y;
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index b2cb101..f024be9 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -1,7 +1,7 @@
 /*
  * Driver for	DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
- * 		DEC VSXXX-GA mouse (rectangular mouse, with ball)
- * 		DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
+ *		DEC VSXXX-GA mouse (rectangular mouse, with ball)
+ *		DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
  *
  * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
  *
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 062848a..c6194a9 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -220,6 +220,7 @@
 	struct mousedev_list *list;
 	struct mousedev_motion *p;
 	unsigned long flags;
+	int wake_readers = 0;
 
 	list_for_each_entry(list, &mousedev->list, node) {
 		spin_lock_irqsave(&list->packet_lock, flags);
@@ -255,11 +256,14 @@
 
 		spin_unlock_irqrestore(&list->packet_lock, flags);
 
-		if (list->ready)
+		if (list->ready) {
 			kill_fasync(&list->fasync, SIGIO, POLL_IN);
+			wake_readers = 1;
+		}
 	}
 
-	wake_up_interruptible(&mousedev->wait);
+	if (wake_readers)
+		wake_up_interruptible(&mousedev->wait);
 }
 
 static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index c978657..d4c990f 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -29,6 +29,7 @@
 
 EXPORT_SYMBOL(ps2_init);
 EXPORT_SYMBOL(ps2_sendbyte);
+EXPORT_SYMBOL(ps2_drain);
 EXPORT_SYMBOL(ps2_command);
 EXPORT_SYMBOL(ps2_schedule_command);
 EXPORT_SYMBOL(ps2_handle_ack);
@@ -45,11 +46,11 @@
 
 
 /*
- * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because when there would
- * be need for retransmissions, the mouse has to be replaced anyway.
+ * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because if there
+ * is a need for retransmissions device has to be replaced anyway.
  *
- * ps2_sendbyte() can only be called from a process context
+ * ps2_sendbyte() can only be called from a process context.
  */
 
 int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
@@ -72,6 +73,91 @@
 }
 
 /*
+ * ps2_drain() waits for device to transmit requested number of bytes
+ * and discards them.
+ */
+
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
+{
+	if (maxbytes > sizeof(ps2dev->cmdbuf)) {
+		WARN_ON(1);
+		maxbytes = sizeof(ps2dev->cmdbuf);
+	}
+
+	down(&ps2dev->cmd_sem);
+
+	serio_pause_rx(ps2dev->serio);
+	ps2dev->flags = PS2_FLAG_CMD;
+	ps2dev->cmdcnt = maxbytes;
+	serio_continue_rx(ps2dev->serio);
+
+	wait_event_timeout(ps2dev->wait,
+			   !(ps2dev->flags & PS2_FLAG_CMD),
+			   msecs_to_jiffies(timeout));
+	up(&ps2dev->cmd_sem);
+}
+
+/*
+ * ps2_is_keyboard_id() checks received ID byte against the list of
+ * known keyboard IDs.
+ */
+
+static inline int ps2_is_keyboard_id(char id_byte)
+{
+	static char keyboard_ids[] = {
+		0xab,	/* Regular keyboards		*/
+		0xac,	/* NCD Sun keyboard		*/
+		0x2b,	/* Trust keyboard, translated	*/
+		0x5d,	/* Trust keyboard		*/
+		0x60,	/* NMB SGI keyboard, translated */
+		0x47,	/* NMB SGI keyboard		*/
+	};
+
+	return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
+}
+
+/*
+ * ps2_adjust_timeout() is called after receiving 1st byte of command
+ * response and tries to reduce remaining timeout to speed up command
+ * completion.
+ */
+
+static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
+{
+	switch (command) {
+		case PS2_CMD_RESET_BAT:
+			/*
+			 * Device has sent the first response byte after
+			 * reset command, reset is thus done, so we can
+			 * shorten the timeout.
+			 * The next byte will come soon (keyboard) or not
+			 * at all (mouse).
+			 */
+			if (timeout > msecs_to_jiffies(100))
+				timeout = msecs_to_jiffies(100);
+			break;
+
+		case PS2_CMD_GETID:
+			/*
+			 * If device behind the port is not a keyboard there
+			 * won't be 2nd byte of ID response.
+			 */
+			if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
+				serio_pause_rx(ps2dev->serio);
+				ps2dev->flags = ps2dev->cmdcnt = 0;
+				serio_continue_rx(ps2dev->serio);
+				timeout = 0;
+			}
+			break;
+
+		default:
+			break;
+	}
+
+	return timeout;
+}
+
+/*
  * ps2_command() sends a command and its parameters to the mouse,
  * then waits for the response and puts it in the param array.
  *
@@ -86,6 +172,11 @@
 	int rc = -1;
 	int i;
 
+	if (receive > sizeof(ps2dev->cmdbuf)) {
+		WARN_ON(1);
+		return -1;
+	}
+
 	down(&ps2dev->cmd_sem);
 
 	serio_pause_rx(ps2dev->serio);
@@ -101,10 +192,9 @@
 	 * ACKing the reset command, and so it can take a long
 	 * time before the ACK arrrives.
 	 */
-	if (command & 0xff)
-		if (ps2_sendbyte(ps2dev, command & 0xff,
-			command == PS2_CMD_RESET_BAT ? 1000 : 200))
-			goto out;
+	if (ps2_sendbyte(ps2dev, command & 0xff,
+			 command == PS2_CMD_RESET_BAT ? 1000 : 200))
+		goto out;
 
 	for (i = 0; i < send; i++)
 		if (ps2_sendbyte(ps2dev, param[i], 200))
@@ -120,33 +210,7 @@
 
 	if (ps2dev->cmdcnt && timeout > 0) {
 
-		if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
-			/*
-			 * Device has sent the first response byte
-			 * after a reset command, reset is thus done,
-			 * shorten the timeout. The next byte will come
-			 * soon (keyboard) or not at all (mouse).
-			 */
-			timeout = msecs_to_jiffies(100);
-		}
-
-		if (command == PS2_CMD_GETID &&
-		    ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
-		    ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
-		    ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
-		    ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
-		    ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
-		    ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
-			/*
-			 * Device behind the port is not a keyboard
-			 * so we don't need to wait for the 2nd byte
-			 * of ID response.
-			 */
-			serio_pause_rx(ps2dev->serio);
-			ps2dev->flags = ps2dev->cmdcnt = 0;
-			serio_continue_rx(ps2dev->serio);
-		}
-
+		timeout = ps2_adjust_timeout(ps2dev, command, timeout);
 		wait_event_timeout(ps2dev->wait,
 				   !(ps2dev->flags & PS2_FLAG_CMD), timeout);
 	}
@@ -160,7 +224,7 @@
 
 	rc = 0;
 
-out:
+ out:
 	serio_pause_rx(ps2dev->serio);
 	ps2dev->flags = 0;
 	serio_continue_rx(ps2dev->serio);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 546ce59..3cdc9ca 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -226,7 +226,7 @@
 			input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
 			input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
 			break;
-		
+
 		case 1: /* 6-byte protocol */
 			input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);
 
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index acb9137..bcfa1e3 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -89,9 +89,9 @@
 #define H3600_SCANCODE_Q	4	 /* 4 -> Q button */
 #define	H3600_SCANCODE_START	5	 /* 5 -> start menu */
 #define	H3600_SCANCODE_UP	6	 /* 6 -> up */
-#define H3600_SCANCODE_RIGHT	7 	 /* 7 -> right */
-#define H3600_SCANCODE_LEFT 	8	 /* 8 -> left */
-#define H3600_SCANCODE_DOWN 	9	 /* 9 -> down */
+#define H3600_SCANCODE_RIGHT	7	 /* 7 -> right */
+#define H3600_SCANCODE_LEFT	8	 /* 8 -> left */
+#define H3600_SCANCODE_DOWN	9	 /* 9 -> down */
 
 static char *h3600_name = "H3600 TouchScreen";
 
@@ -113,7 +113,7 @@
 
 static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-        int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
+	int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
 	struct input_dev *dev = (struct input_dev *) dev_id;
 
 	input_regs(dev, regs);
@@ -125,7 +125,7 @@
 
 static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-        int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
+	int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
 	struct input_dev *dev = (struct input_dev *) dev_id;
 
 	/*
@@ -145,8 +145,8 @@
 static int flite_brightness = 25;
 
 enum flite_pwr {
-        FLITE_PWR_OFF = 0,
-        FLITE_PWR_ON = 1
+	FLITE_PWR_OFF = 0,
+	FLITE_PWR_ON = 1
 };
 
 /*
@@ -157,9 +157,9 @@
 	struct h3600_dev *ts = dev->private;
 
 	/* Must be in this order */
-       	ts->serio->write(ts->serio, 1);
+	ts->serio->write(ts->serio, 1);
 	ts->serio->write(ts->serio, pwr);
-      	ts->serio->write(ts->serio, brightness);
+	ts->serio->write(ts->serio, brightness);
 	return 0;
 }
 
@@ -169,26 +169,26 @@
 {
 	struct input_dev *dev = (struct input_dev *) data;
 
-        switch (req) {
-        case PM_SUSPEND: /* enter D1-D3 */
-                suspended = 1;
-                h3600_flite_power(dev, FLITE_PWR_OFF);
-                break;
-        case PM_BLANK:
-                if (!suspended)
-                        h3600_flite_power(dev, FLITE_PWR_OFF);
-                break;
-        case PM_RESUME:  /* enter D0 */
-                /* same as unblank */
-        case PM_UNBLANK:
-                if (suspended) {
-                        //initSerial();
-                        suspended = 0;
-                }
-                h3600_flite_power(dev, FLITE_PWR_ON);
-                break;
-        }
-        return 0;
+	switch (req) {
+	case PM_SUSPEND: /* enter D1-D3 */
+		suspended = 1;
+		h3600_flite_power(dev, FLITE_PWR_OFF);
+		break;
+	case PM_BLANK:
+		if (!suspended)
+			h3600_flite_power(dev, FLITE_PWR_OFF);
+		break;
+	case PM_RESUME:  /* enter D0 */
+		/* same as unblank */
+	case PM_UNBLANK:
+		if (suspended) {
+			//initSerial();
+			suspended = 0;
+		}
+		h3600_flite_power(dev, FLITE_PWR_ON);
+		break;
+	}
+	return 0;
 }
 #endif
 
@@ -199,25 +199,25 @@
  */
 static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
 {
-        struct input_dev *dev = &ts->dev;
+	struct input_dev *dev = &ts->dev;
 	static int touched = 0;
 	int key, down = 0;
 
 	input_regs(dev, regs);
 
-        switch (ts->event) {
-                /*
-                   Buttons - returned as a single byte
-                        7 6 5 4 3 2 1 0
-                        S x x x N N N N
+	switch (ts->event) {
+		/*
+		   Buttons - returned as a single byte
+			7 6 5 4 3 2 1 0
+			S x x x N N N N
 
-                   S       switch state ( 0=pressed 1=released)
-                   x       Unused.
-                   NNNN    switch number 0-15
+		   S       switch state ( 0=pressed 1=released)
+		   x       Unused.
+		   NNNN    switch number 0-15
 
-                Note: This is true for non interrupt generated key events.
-                */
-                case KEYBD_ID:
+		   Note: This is true for non interrupt generated key events.
+		*/
+		case KEYBD_ID:
 			down = (ts->buf[0] & 0x80) ? 0 : 1;
 
 			switch (ts->buf[0] & 0x7f) {
@@ -229,40 +229,40 @@
                                         break;
 				case H3600_SCANCODE_CONTACTS:
 					key = KEY_PROG2;
-                                        break;
+					break;
 				case H3600_SCANCODE_Q:
 					key = KEY_Q;
-                                        break;
+					break;
 				case H3600_SCANCODE_START:
 					key = KEY_PROG3;
-                                        break;
+					break;
 				case H3600_SCANCODE_UP:
 					key = KEY_UP;
-                                        break;
+					break;
 				case H3600_SCANCODE_RIGHT:
 					key = KEY_RIGHT;
-                                        break;
+					break;
 				case H3600_SCANCODE_LEFT:
 					key = KEY_LEFT;
-                                        break;
+					break;
 				case H3600_SCANCODE_DOWN:
 					key = KEY_DOWN;
-                                        break;
+					break;
 				default:
 					key = 0;
 			}
-                        if (key)
-                        	input_report_key(dev, key, down);
-                        break;
-                /*
-                 * Native touchscreen event data is formatted as shown below:-
-                 *
-                 *      +-------+-------+-------+-------+
-                 *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
-                 *      +-------+-------+-------+-------+
-                 *       byte 0    1       2       3
-                 */
-                case TOUCHS_ID:
+			if (key)
+				input_report_key(dev, key, down);
+			break;
+		/*
+		 * Native touchscreen event data is formatted as shown below:-
+		 *
+		 *      +-------+-------+-------+-------+
+		 *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
+		 *      +-------+-------+-------+-------+
+		 *       byte 0    1       2       3
+		 */
+		case TOUCHS_ID:
 			if (!touched) {
 				input_report_key(dev, BTN_TOUCH, 1);
 				touched = 1;
@@ -272,19 +272,19 @@
 				unsigned short x, y;
 
 				x = ts->buf[0]; x <<= 8; x += ts->buf[1];
-                                y = ts->buf[2]; y <<= 8; y += ts->buf[3];
+				y = ts->buf[2]; y <<= 8; y += ts->buf[3];
 
-                       		input_report_abs(dev, ABS_X, x);
-                       		input_report_abs(dev, ABS_Y, y);
+				input_report_abs(dev, ABS_X, x);
+				input_report_abs(dev, ABS_Y, y);
 			} else {
-		               	input_report_key(dev, BTN_TOUCH, 0);
+				input_report_key(dev, BTN_TOUCH, 0);
 				touched = 0;
 			}
-                        break;
+			break;
 		default:
 			/* Send a non input event elsewhere */
 			break;
-        }
+	}
 
 	input_sync(dev);
 }
@@ -293,7 +293,7 @@
  * h3600ts_event() handles events from the input module.
  */
 static int h3600ts_event(struct input_dev *dev, unsigned int type,
-		 	 unsigned int code, int value)
+			 unsigned int code, int value)
 {
 	struct h3600_dev *ts = dev->private;
 
@@ -332,41 +332,41 @@
 static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
                                      unsigned int flags, struct pt_regs *regs)
 {
-        struct h3600_dev *ts = serio_get_drvdata(serio);
+	struct h3600_dev *ts = serio_get_drvdata(serio);
 
 	/*
-         * We have a new frame coming in.
-         */
+	 * We have a new frame coming in.
+	 */
 	switch (state) {
 		case STATE_SOF:
-        		if (data == CHAR_SOF)
-                		state = STATE_ID;
+			if (data == CHAR_SOF)
+				state = STATE_ID;
 			break;
-        	case STATE_ID:
+		case STATE_ID:
 			ts->event = (data & 0xf0) >> 4;
 			ts->len = (data & 0xf);
 			ts->idx = 0;
 			if (ts->event >= MAX_ID) {
 				state = STATE_SOF;
-                        	break;
+				break;
 			}
 			ts->chksum = data;
-                	state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
+			state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
 			break;
 		case STATE_DATA:
 			ts->chksum += data;
 			ts->buf[ts->idx]= data;
-			if(++ts->idx == ts->len)
-                        	state = STATE_EOF;
+			if (++ts->idx == ts->len)
+				state = STATE_EOF;
 			break;
 		case STATE_EOF:
-                	state = STATE_SOF;
-                	if (data == CHAR_EOF || data == ts->chksum)
+			state = STATE_SOF;
+			if (data == CHAR_EOF || data == ts->chksum)
 				h3600ts_process_packet(ts, regs);
-                	break;
-        	default:
-                	printk("Error3\n");
-                	break;
+			break;
+		default:
+			printk("Error3\n");
+			break;
 	}
 
 	return IRQ_HANDLED;
@@ -390,10 +390,10 @@
 	init_input_dev(&ts->dev);
 
 	/* Device specific stuff */
-        set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
-        set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
+	set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
+	set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 
-        if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
+	if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
 			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
 			"h3600_action", &ts->dev)) {
 		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
@@ -401,7 +401,7 @@
 		return -EBUSY;
 	}
 
-        if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
+	if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
 			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
 			"h3600_suspend", &ts->dev)) {
 		free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
@@ -433,7 +433,7 @@
 
 	sprintf(ts->phys, "%s/input0", serio->phys);
 
-       	ts->dev.event = h3600ts_event;
+	ts->dev.event = h3600ts_event;
 	ts->dev.private = ts;
 	ts->dev.name = h3600_name;
 	ts->dev.phys = ts->phys;
@@ -446,8 +446,8 @@
 
 	err = serio_open(serio, drv);
 	if (err) {
-        	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
-        	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
+		free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
+		free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
 		serio_set_drvdata(serio, NULL);
 		kfree(ts);
 		return err;
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index 2d14a57..afaaebe 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -17,7 +17,7 @@
  * found in Gateway AOL Connected Touchpad computers.
  *
  * Documentation for ICS MK712 can be found at:
- * 	http://www.icst.com/pdf/mk712.pdf
+ *	http://www.icst.com/pdf/mk712.pdf
  */
 
 /*
@@ -77,7 +77,6 @@
 #define MK712_READ_ONE_POINT			0x20
 #define MK712_POWERUP				0x40
 
-static int mk712_used = 0;
 static struct input_dev mk712_dev;
 static DEFINE_SPINLOCK(mk712_lock);
 
@@ -130,17 +129,14 @@
 
 	spin_lock_irqsave(&mk712_lock, flags);
 
-	if (!mk712_used++) {
+	outb(0, mk712_io + MK712_CONTROL); /* Reset */
 
-		outb(0, mk712_io + MK712_CONTROL); /* Reset */
+	outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
+		MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
+		MK712_ENABLE_PERIODIC_CONVERSIONS |
+		MK712_POWERUP, mk712_io + MK712_CONTROL);
 
-		outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
-			MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
-			MK712_ENABLE_PERIODIC_CONVERSIONS |
-			MK712_POWERUP, mk712_io + MK712_CONTROL);
-
-		outb(10, mk712_io + MK712_RATE); /* 187 points per second */
-	}
+	outb(10, mk712_io + MK712_RATE); /* 187 points per second */
 
 	spin_unlock_irqrestore(&mk712_lock, flags);
 
@@ -153,8 +149,7 @@
 
 	spin_lock_irqsave(&mk712_lock, flags);
 
-	if (!--mk712_used)
-		outb(0, mk712_io + MK712_CONTROL);
+	outb(0, mk712_io + MK712_CONTROL);
 
 	spin_unlock_irqrestore(&mk712_lock, flags);
 }
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 8a7117a..91691a6 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -86,33 +86,18 @@
 	  on the "SMU" system control chip which replaces the old PMU.
 	  If you don't know, say Y.
 
-config PMAC_PBOOK
-	bool "Power management support for PowerBooks"
-	depends on ADB_PMU
-	---help---
-	  This provides support for putting a PowerBook to sleep; it also
-	  enables media bay support.  Power management works on the
-	  PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
-	  the Titanium Powerbook G4, as well as the iBooks.  You should get
-	  the power management daemon, pmud, to make it work and you must have
-	  the /dev/pmu device (see the pmud README).
-
-	  Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
-
-	  If you have a PowerBook, you should say Y here.
-
-	  You may also want to compile the dma sound driver as a module and
-	  have it autoloaded. The act of removing the module shuts down the
-	  sound hardware for more power savings.
-
-config PM
-	bool
-	depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
-	default y
-
 config PMAC_APM_EMU
 	tristate "APM emulation"
-	depends on PMAC_PBOOK
+	depends on PPC_PMAC && PPC32 && PM
+
+config PMAC_MEDIABAY
+	bool "Support PowerBook hotswap media bay"
+	depends on PPC_PMAC && PPC32
+	help
+	  This option adds support for older PowerBook's hotswap media bay
+	  that can contains batteries, floppy drives, or IDE devices. PCI
+	  devices are not fully supported in the bay as I never had one to
+	  try with
 
 # made a separate option since backlight may end up beeing used
 # on non-powerbook machines (but only on PMU based ones AFAIK)
@@ -126,13 +111,6 @@
 	  events; also, the PowerBook button device will be enabled so you can
 	  change the screen brightness.
 
-config MAC_SERIAL
-	tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)"
-	depends on PPC_PMAC && BROKEN
-	help
-	  This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in
-	  "Character devices --> Serial drivers --> PowerMac z85c30" option.
-
 config ADB_MACIO
 	bool "Include MacIO (CHRP) ADB driver"
 	depends on ADB && PPC_CHRP && !PPC_PMAC64
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index c3a4705..f5ae171 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -6,8 +6,7 @@
 
 obj-$(CONFIG_PPC_PMAC)		+= macio_asic.o
 
-obj-$(CONFIG_PMAC_PBOOK)	+= mediabay.o
-obj-$(CONFIG_MAC_SERIAL)	+= macserial.o
+obj-$(CONFIG_PMAC_MEDIABAY)	+= mediabay.o
 obj-$(CONFIG_MAC_EMUMOUSEBTN)	+= mac_hid.o
 obj-$(CONFIG_INPUT_ADBHID)	+= adbhid.o
 obj-$(CONFIG_ANSLCD)		+= ans-lcd.o
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 493e2af..c0dc1e3 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -90,7 +90,7 @@
 static int autopoll_devs;
 int __adb_probe_sync;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
 static struct pmu_sleep_notifier adb_sleep_notifier = {
 	adb_notify_sleep,
@@ -320,9 +320,9 @@
 		printk(KERN_WARNING "Warning: no ADB interface detected\n");
 		adb_controller = NULL;
 	} else {
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 		pmu_register_sleep_notifier(&adb_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 #ifdef CONFIG_PPC
 		if (machine_is_compatible("AAPL,PowerBook1998") ||
 			machine_is_compatible("PowerBook1,1"))
@@ -337,7 +337,7 @@
 
 __initcall(adb_init);
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * notify clients before sleep and reset bus afterwards
  */
@@ -378,7 +378,7 @@
 	}
 	return PBOOK_SLEEP_OK;
 }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 static int
 do_adb_reset_bus(void)
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
deleted file mode 100644
index 0be3ac6..0000000
--- a/drivers/macintosh/macserial.c
+++ /dev/null
@@ -1,3036 +0,0 @@
-/*
- * macserial.c: Serial port driver for Power Macintoshes.
- *
- * 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)
- *
- * Receive DMA code by Takashi Oe <toe@unlserve.unl.edu>.
- *
- * $Id: macserial.c,v 1.24.2.4 1999/10/19 04:36:42 paulus Exp $
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.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 <linux/init.h>
-#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
-#endif
-#include <linux/slab.h>
-#include <linux/bitops.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-#include <asm/dbdma.h>
-
-#include "macserial.h"
-
-#ifdef CONFIG_PMAC_PBOOK
-static int serial_notify_sleep(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier serial_sleep_notifier = {
-	serial_notify_sleep,
-	SLEEP_LEVEL_MISC,
-};
-#endif
-
-#define SUPPORT_SERIAL_DMA
-#define MACSERIAL_VERSION	"2.0"
-
-/*
- * 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 */
-
-/* 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()
-
-static struct tty_driver *serial_driver;
-
-struct mac_zschannel zs_channels[NUM_CHANNELS];
-
-struct mac_serial zs_soft[NUM_CHANNELS];
-int zs_channels_found;
-struct mac_serial *zs_chain;	/* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-
-static int is_powerbook;
-
-#ifdef CONFIG_SERIAL_CONSOLE
-static struct console sercons;
-#endif
-
-#ifdef CONFIG_KGDB
-struct mac_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
-	9,  0x80,	/* reset A side (CHRA) */
-	13, 0,		/* set baud rate divisor */
-	12, 1,
-	14, 1,		/* baud rate gen enable, src=rtxc (BRENABL) */
-	11, 0x50,	/* clocks = br gen (RCBR | TCBR) */
-	5,  0x6a,	/* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
-	4,  0x44,	/* x16 clock, 1 stop (SB1 | X16CLK)*/
-	3,  0xc1,	/* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-#endif
-#define ZS_CLOCK         3686400 	/* Z8530 RTxC input clock rate */
-
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL	1
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * Debugging.
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_POWER
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_STOP
-#undef SERIAL_DEBUG_BAUDS
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-#define _INLINE_ inline
-
-#ifdef SERIAL_DEBUG_OPEN
-#define OPNDBG(fmt, arg...)	printk(KERN_DEBUG fmt , ## arg)
-#else
-#define OPNDBG(fmt, arg...)	do { } while (0)
-#endif
-#ifdef SERIAL_DEBUG_POWER
-#define PWRDBG(fmt, arg...)	printk(KERN_DEBUG fmt , ## arg)
-#else
-#define PWRDBG(fmt, arg...)	do { } while (0)
-#endif
-#ifdef SERIAL_DEBUG_BAUDS
-#define BAUDBG(fmt, arg...)	printk(fmt , ## arg)
-#else
-#define BAUDBG(fmt, arg...)	do { } while (0)
-#endif
-
-static void probe_sccs(void);
-static void change_speed(struct mac_serial *info, struct termios *old);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static int set_scc_power(struct mac_serial * info, int state);
-static int setup_scc(struct mac_serial * info);
-static void dbdma_reset(volatile struct dbdma_regs *dma);
-static void dbdma_flush(volatile struct dbdma_regs *dma);
-static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
-static void dma_init(struct mac_serial * info);
-static void rxdma_start(struct mac_serial * info, int curr);
-static void rxdma_to_tty(struct mac_serial * info);
-
-/*
- * 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);
-
-
-static inline int __pmac
-serial_paranoia_check(struct mac_serial *info,
-		      char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-	static const char badmagic[] = KERN_WARNING
-		"Warning: bad magic number for serial struct %s in %s\n";
-	static const char badinfo[] = KERN_WARNING
-		"Warning: null mac_serial for %s in %s\n";
-
-	if (!info) {
-		printk(badinfo, name, routine);
-		return 1;
-	}
-	if (info->magic != SERIAL_MAGIC) {
-		printk(badmagic, name, routine);
-		return 1;
-	}
-#endif
-	return 0;
-}
-
-/* 
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char __pmac read_zsreg(struct mac_zschannel *channel,
-					      unsigned char reg)
-{
-	unsigned char retval;
-	unsigned long flags;
-
-	/*
-	 * We have to make this atomic.
-	 */
-	spin_lock_irqsave(&channel->lock, flags);
-	if (reg != 0) {
-		*channel->control = reg;
-		RECOVERY_DELAY;
-	}
-	retval = *channel->control;
-	RECOVERY_DELAY;
-	spin_unlock_irqrestore(&channel->lock, flags);
-	return retval;
-}
-
-static inline void __pmac write_zsreg(struct mac_zschannel *channel,
-				      unsigned char reg, unsigned char value)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&channel->lock, flags);
-	if (reg != 0) {
-		*channel->control = reg;
-		RECOVERY_DELAY;
-	}
-	*channel->control = value;
-	RECOVERY_DELAY;
-	spin_unlock_irqrestore(&channel->lock, flags);
-	return;
-}
-
-static inline unsigned char __pmac 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 mac_serial *ss, int set)
-{
-	if (set)
-		ss->curregs[5] |= (RTS | DTR);
-	else
-		ss->curregs[5] &= ~(RTS | DTR);
-	write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
-	return;
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct mac_serial *ss)
-{
-	struct mac_zschannel *channel = ss->zs_channel;
-	int brg;
-
-	if ((ss->curregs[R11] & TCBR) == 0) {
-		/* higher rates don't use the baud rate generator */
-		return (ss->curregs[R4] & X32CLK)? ZS_CLOCK/32: ZS_CLOCK/16;
-	}
-	/* 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->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct mac_zschannel *zsc)
-{
-	write_zsreg(zsc, 0, ERR_RES);
-	write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * Reset a Descriptor-Based DMA channel.
- */
-static void dbdma_reset(volatile struct dbdma_regs *dma)
-{
-	int i;
-
-	out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
-
-	/*
-	 * Yes this looks peculiar, but apparently it needs to be this
-	 * way on some machines.  (We need to make sure the DBDMA
-	 * engine has actually got the write above and responded
-	 * to it. - paulus)
-	 */
-	for (i = 200; i > 0; --i)
-		if (ld_le32(&dma->status) & RUN)
-			udelay(1);
-}
-
-/*
- * Tells a DBDMA channel to stop and write any buffered data
- * it might have to memory.
- */
-static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma)
-{
-	int i = 0;
-
-	out_le32(&dma->control, (FLUSH << 16) | FLUSH);
-	while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100))
-		udelay(1);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * 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
- * -----------------------------------------------------------------------
- */
-
-/*
- * 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 mac_serial *info,
-				  int event)
-{
-	info->event |= 1 << event;
-	schedule_work(&info->tqueue);
-}
-
-/* Work out the flag value for a z8530 status value. */
-static _INLINE_ int stat_to_flag(int stat)
-{
-	int flag;
-
-	if (stat & Rx_OVR) {
-		flag = TTY_OVERRUN;
-	} else if (stat & FRM_ERR) {
-		flag = TTY_FRAME;
-	} else if (stat & PAR_ERR) {
-		flag = TTY_PARITY;
-	} else
-		flag = 0;
-	return flag;
-}
-
-static _INLINE_ void receive_chars(struct mac_serial *info,
-				   struct pt_regs *regs)
-{
-	struct tty_struct *tty = info->tty;
-	unsigned char ch, stat, flag;
-
-	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
-
-		stat = read_zsreg(info->zs_channel, R1);
-		ch = read_zsdata(info->zs_channel);
-
-#ifdef CONFIG_KGDB
-		if (info->kgdb_channel) {
-			if (ch == 0x03 || ch == '$')
-				breakpoint();
-			if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
-				write_zsreg(info->zs_channel, 0, ERR_RES);
-			return;
-		}
-#endif
-		if (!tty)
-			continue;
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-			tty_flip_buffer_push(tty);
-
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-			static int flip_buf_ovf;
-			if (++flip_buf_ovf <= 1)
-				printk(KERN_WARNING "FB. overflow: %d\n",
-						    flip_buf_ovf);
-			break;
-		}
-		tty->flip.count++;
-		{
-			static int flip_max_cnt;
-			if (flip_max_cnt < tty->flip.count)
-				flip_max_cnt = tty->flip.count;
-		}
-		flag = stat_to_flag(stat);
-		if (flag)
-			/* reset the error indication */
-			write_zsreg(info->zs_channel, 0, ERR_RES);
-		*tty->flip.flag_buf_ptr++ = flag;
-		*tty->flip.char_buf_ptr++ = ch;
-	}
-	if (tty)
-		tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct mac_serial *info)
-{
-	if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
-		return;
-	info->tx_active = 0;
-
-	if (info->x_char && !info->power_wait) {
-		/* Send next char */
-		write_zsdata(info->zs_channel, info->x_char);
-		info->x_char = 0;
-		info->tx_active = 1;
-		return;
-	}
-
-	if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped
-	    || info->power_wait) {
-		write_zsreg(info->zs_channel, 0, RES_Tx_P);
-		return;
-	}
-
-	/* Send char */
-	write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
-	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-	info->xmit_cnt--;
-	info->tx_active = 1;
-
-	if (info->xmit_cnt < WAKEUP_CHARS)
-		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void powerup_done(unsigned long data)
-{
-	struct mac_serial *info = (struct mac_serial *) data;
-	unsigned long flags;
-
-	spin_lock_irqsave(&info->lock, flags);
-	info->power_wait = 0;
-	transmit_chars(info);
-	spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static _INLINE_ void status_handle(struct mac_serial *info)
-{
-	unsigned char status;
-
-	/* Get status from Read Register 0 */
-	status = read_zsreg(info->zs_channel, 0);
-
-	/* Check for DCD transitions */
-	if (((status ^ info->read_reg_zero) & DCD) != 0
-	    && info->tty && !C_CLOCAL(info->tty)) {
-		if (status & DCD) {
-			wake_up_interruptible(&info->open_wait);
-		} else {
-			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->tx_stopped) {
-#ifdef SERIAL_DEBUG_FLOW
-				printk(KERN_DEBUG "CTS up\n");
-#endif
-				info->tx_stopped = 0;
-				if (!info->tx_active)
-					transmit_chars(info);
-			}
-		} else {
-#ifdef SERIAL_DEBUG_FLOW
-			printk(KERN_DEBUG "CTS down\n");
-#endif
-			info->tx_stopped = 1;
-		}
-	}
-
-	/* Clear status condition... */
-	write_zsreg(info->zs_channel, 0, RES_EXT_INT);
-	info->read_reg_zero = status;
-}
-
-static _INLINE_ void receive_special_dma(struct mac_serial *info)
-{
-	unsigned char stat, flag;
-	volatile struct dbdma_regs *rd = &info->rx->dma;
-	int where = RX_BUF_SIZE;
-
-	spin_lock(&info->rx_dma_lock);
-	if ((ld_le32(&rd->status) & ACTIVE) != 0)
-		dbdma_flush(rd);
-	if (in_le32(&rd->cmdptr)
-	    == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
-		where -= in_le16(&info->rx->res_count);
-	where--;
-
-	stat = read_zsreg(info->zs_channel, R1);
-
-	flag = stat_to_flag(stat);
-	if (flag) {
-		info->rx_flag_buf[info->rx_cbuf][where] = flag;
-		/* reset the error indication */
-		write_zsreg(info->zs_channel, 0, ERR_RES);
-	}
-
-	spin_unlock(&info->rx_dma_lock);
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct mac_serial *info = (struct mac_serial *) dev_id;
-	unsigned char zs_intreg;
-	int shift;
-	unsigned long flags;
-	int handled = 0;
-
-	if (!(info->flags & ZILOG_INITIALIZED)) {
-		printk(KERN_WARNING "rs_interrupt: irq %d, port not "
-				    "initialized\n", irq);
-		disable_irq(irq);
-		return IRQ_NONE;
-	}
-
-	/* 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)
-
-	if (info->zs_chan_a == info->zs_channel)
-		shift = 3;	/* Channel A */
-	else
-		shift = 0;	/* Channel B */
-
-	spin_lock_irqsave(&info->lock, flags);
-	for (;;) {
-		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
-#ifdef SERIAL_DEBUG_INTR
-		printk(KERN_DEBUG "rs_interrupt: irq %d, zs_intreg 0x%x\n",
-		       irq, (int)zs_intreg);
-#endif
-
-		if ((zs_intreg & CHAN_IRQMASK) == 0)
-			break;
-		handled = 1;
-
-		if (zs_intreg & CHBRxIP) {
-			/* If we are doing DMA, we only ask for interrupts
-			   on characters with errors or special conditions. */
-			if (info->dma_initted)
-				receive_special_dma(info);
-			else
-				receive_chars(info, regs);
-		}
-		if (zs_intreg & CHBTxIP)
-			transmit_chars(info);
-		if (zs_intreg & CHBEXT)
-			status_handle(info);
-	}
-	spin_unlock_irqrestore(&info->lock, flags);
-	return IRQ_RETVAL(handled);
-}
-
-/* Transmit DMA interrupt - not used at present */
-static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	return IRQ_HANDLED;
-}
-
-/*
- * Receive DMA interrupt.
- */
-static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct mac_serial *info = (struct mac_serial *) dev_id;
-	volatile struct dbdma_cmd *cd;
-
-	if (!info->dma_initted)
-		return IRQ_NONE;
-	spin_lock(&info->rx_dma_lock);
-	/* First, confirm that this interrupt is, indeed, coming */
-	/* from Rx DMA */
-	cd = info->rx_cmds[info->rx_cbuf] + 2;
-	if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) {
-		spin_unlock(&info->rx_dma_lock);
-		return IRQ_NONE;
-	}
-	if (info->rx_fbuf != RX_NO_FBUF) {
-		info->rx_cbuf = info->rx_fbuf;
-		if (++info->rx_fbuf == info->rx_nbuf)
-			info->rx_fbuf = 0;
-		if (info->rx_fbuf == info->rx_ubuf)
-			info->rx_fbuf = RX_NO_FBUF;
-	}
-	spin_unlock(&info->rx_dma_lock);
-	return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
-	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-
-#ifdef SERIAL_DEBUG_STOP
-	printk(KERN_DEBUG "rs_stop %ld....\n",
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_stop"))
-		return;
-
-#if 0
-	spin_lock_irqsave(&info->lock, flags);
-	if (info->curregs[5] & TxENAB) {
-		info->curregs[5] &= ~TxENAB;
-		info->pendregs[5] &= ~TxENAB;
-		write_zsreg(info->zs_channel, 5, info->curregs[5]);
-	}
-	spin_unlock_irqrestore(&info->lock, flags);
-#endif
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-	unsigned long flags;
-
-#ifdef SERIAL_DEBUG_STOP
-	printk(KERN_DEBUG "rs_start %ld....\n", 
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_start"))
-		return;
-
-	spin_lock_irqsave(&info->lock, flags);
-#if 0
-	if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
-		info->curregs[5] |= TxENAB;
-		info->pendregs[5] = info->curregs[5];
-		write_zsreg(info->zs_channel, 5, info->curregs[5]);
-	}
-#else
-	if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
-		transmit_chars(info);
-	}
-#endif
-	spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void do_softint(void *private_)
-{
-	struct mac_serial	*info = (struct mac_serial *) private_;
-	struct tty_struct	*tty;
-
-	tty = info->tty;
-	if (!tty)
-		return;
-
-	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-		tty_wakeup(tty);
-}
-
-static int startup(struct mac_serial * info)
-{
-	int delay;
-
-	OPNDBG("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
- 
-	if (info->flags & ZILOG_INITIALIZED) {
-		OPNDBG(" -> already inited\n");
- 		return 0;
-	}
-
-	if (!info->xmit_buf) {
-		info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
-		if (!info->xmit_buf)
-			return -ENOMEM;
-	}
-
-	OPNDBG("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-
-	delay = set_scc_power(info, 1);
-
-	setup_scc(info);
-
-	if (delay) {
-		unsigned long flags;
-
-		/* delay is in ms */
-		spin_lock_irqsave(&info->lock, flags);
-		info->power_wait = 1;
-		mod_timer(&info->powerup_timer,
-			  jiffies + (delay * HZ + 999) / 1000);
-		spin_unlock_irqrestore(&info->lock, flags);
-	}
-
-	OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
-
-	info->flags |= ZILOG_INITIALIZED;
-	enable_irq(info->irq);
-	if (info->dma_initted) {
-		enable_irq(info->rx_dma_irq);
-	}
-
-	return 0;
-}
-
-static _INLINE_ void rxdma_start(struct mac_serial * info, int curr)
-{
-	volatile struct dbdma_regs *rd = &info->rx->dma;
-	volatile struct dbdma_cmd *cd = info->rx_cmds[curr];
-
-//printk(KERN_DEBUG "SCC: rxdma_start\n");
-
-	st_le32(&rd->cmdptr, virt_to_bus(cd));
-	out_le32(&rd->control, (RUN << 16) | RUN);
-}
-
-static void rxdma_to_tty(struct mac_serial *info)
-{
-	struct tty_struct	*tty = info->tty;
-	volatile struct dbdma_regs *rd = &info->rx->dma;
-	unsigned long flags;
-	int residue, available, space, do_queue;
-
-	if (!tty)
-		return;
-
-	do_queue = 0;
-	spin_lock_irqsave(&info->rx_dma_lock, flags);
-more:
-	space = TTY_FLIPBUF_SIZE - tty->flip.count;
-	if (!space) {
-		do_queue++;
-		goto out;
-	}
-	residue = 0;
-	if (info->rx_ubuf == info->rx_cbuf) {
-		if ((ld_le32(&rd->status) & ACTIVE) != 0) {
-			dbdma_flush(rd);
-			if (in_le32(&rd->cmdptr)
-			    == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1))
-				residue = in_le16(&info->rx->res_count);
-		}
-	}
-	available = RX_BUF_SIZE - residue - info->rx_done_bytes;
-	if (available > space)
-		available = space;
-	if (available) {
-		memcpy(tty->flip.char_buf_ptr,
-		       info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes,
-		       available);
-		memcpy(tty->flip.flag_buf_ptr,
-		       info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
-		       available);
-		tty->flip.char_buf_ptr += available;
-		tty->flip.count += available;
-		tty->flip.flag_buf_ptr += available;
-		memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
-		       0, available);
-		info->rx_done_bytes += available;
-		do_queue++;
-	}
-	if (info->rx_done_bytes == RX_BUF_SIZE) {
-		volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf];
-
-		if (info->rx_ubuf == info->rx_cbuf)
-			goto out;
-		/* mark rx_char_buf[rx_ubuf] free */
-		st_le16(&cd->command, DBDMA_NOP);
-		cd++;
-		st_le32(&cd->cmd_dep, 0);
-		st_le32((unsigned int *)&cd->res_count, 0);
-		cd++;
-		st_le16(&cd->xfer_status, 0);
-
-		if (info->rx_fbuf == RX_NO_FBUF) {
-			info->rx_fbuf = info->rx_ubuf;
-			if (!(ld_le32(&rd->status) & ACTIVE)) {
-				dbdma_reset(&info->rx->dma);
-				rxdma_start(info, info->rx_ubuf);
-				info->rx_cbuf = info->rx_ubuf;
-			}
-		}
-		info->rx_done_bytes = 0;
-		if (++info->rx_ubuf == info->rx_nbuf)
-			info->rx_ubuf = 0;
-		if (info->rx_fbuf == info->rx_ubuf)
-			info->rx_fbuf = RX_NO_FBUF;
-		goto more;
-	}
-out:
-	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
-	if (do_queue)
-		tty_flip_buffer_push(tty);
-}
-
-static void poll_rxdma(unsigned long private_)
-{
-	struct mac_serial	*info = (struct mac_serial *) private_;
-	unsigned long flags;
-
-	rxdma_to_tty(info);
-	spin_lock_irqsave(&info->rx_dma_lock, flags);
-	mod_timer(&info->poll_dma_timer, RX_DMA_TIMER);
-	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
-}
-
-static void dma_init(struct mac_serial * info)
-{
-	int i, size;
-	volatile struct dbdma_cmd *cd;
-	unsigned char *p;
-
-	info->rx_nbuf = 8;
-
-	/* various mem set up */
-	size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2)
-		+ (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds)
-		   + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf))
-		* info->rx_nbuf;
-	info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA);
-	if (info->dma_priv == NULL)
-		return;
-	memset(info->dma_priv, 0, size);
-
-	info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv;
-	info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf);
-	info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf;
-	p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf);
-	for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
-		info->rx_char_buf[i] = p;
-	for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
-		info->rx_flag_buf[i] = p;
-
-	/* a bit of DMA programming */
-	cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p);
-	st_le16(&cd->command, DBDMA_NOP);
-	cd++;
-	st_le16(&cd->req_count, RX_BUF_SIZE);
-	st_le16(&cd->command, INPUT_MORE);
-	st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0]));
-	cd++;
-	st_le16(&cd->req_count, 4);
-	st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
-	st_le32(&cd->phy_addr, virt_to_bus(cd-2));
-	st_le32(&cd->cmd_dep, DBDMA_STOP);
-	for (i = 1; i < info->rx_nbuf; i++) {
-		info->rx_cmds[i] = ++cd;
-		st_le16(&cd->command, DBDMA_NOP);
-		cd++;
-		st_le16(&cd->req_count, RX_BUF_SIZE);
-		st_le16(&cd->command, INPUT_MORE);
-		st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i]));
-		cd++;
-		st_le16(&cd->req_count, 4);
-		st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
-		st_le32(&cd->phy_addr, virt_to_bus(cd-2));
-		st_le32(&cd->cmd_dep, DBDMA_STOP);
-	}
-	cd++;
-	st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS);
-	st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0]));
-
-	/* setup DMA to our liking */
-	dbdma_reset(&info->rx->dma);
-	st_le32(&info->rx->dma.intr_sel, 0x10001);
-	st_le32(&info->rx->dma.br_sel, 0x10001);
-	out_le32(&info->rx->dma.wait_sel, 0x10001);
-
-	/* set various flags */
-	info->rx_ubuf = 0;
-	info->rx_cbuf = 0;
-	info->rx_fbuf = info->rx_ubuf + 1;
-	if (info->rx_fbuf == info->rx_nbuf)
-		info->rx_fbuf = RX_NO_FBUF;
-	info->rx_done_bytes = 0;
-
-	/* setup polling */
-	init_timer(&info->poll_dma_timer);
-	info->poll_dma_timer.function = (void *)&poll_rxdma;
-	info->poll_dma_timer.data = (unsigned long)info;
-
-	info->dma_initted = 1;
-}
-
-/*
- * FixZeroBug....Works around a bug in the SCC receving channel.
- * Taken from Darwin code, 15 Sept. 2000  -DanM
- *
- * The following sequence prevents a problem that is seen with O'Hare ASICs
- * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
- * at the input to the receiver becomes 'stuck' and locks up the receiver.
- * This problem can occur as a result of a zero bit at the receiver input
- * coincident with any of the following events:
- *
- *	The SCC is initialized (hardware or software).
- *	A framing error is detected.
- *	The clocking option changes from synchronous or X1 asynchronous
- *		clocking to X16, X32, or X64 asynchronous clocking.
- *	The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
- *
- * This workaround attempts to recover from the lockup condition by placing
- * the SCC in synchronous loopback mode with a fast clock before programming
- * any of the asynchronous modes.
- */
-static void fix_zero_bug_scc(struct mac_serial * info)
-{
-	write_zsreg(info->zs_channel, 9,
-		    (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
-	udelay(10);
-	write_zsreg(info->zs_channel, 9,
-		    ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV));
-
-	write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC));
-
-	/* I think this is wrong....but, I just copying code....
-	*/
-	write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
-
-	write_zsreg(info->zs_channel, 5, (8 & ~TxENAB));
-	write_zsreg(info->zs_channel, 9, NV);	/* Didn't we already do this? */
-	write_zsreg(info->zs_channel, 11, (RCBR | TCBR));
-	write_zsreg(info->zs_channel, 12, 0);
-	write_zsreg(info->zs_channel, 13, 0);
-	write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR));
-	write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL));
-	write_zsreg(info->zs_channel, 3, (8 | RxENABLE));
-	write_zsreg(info->zs_channel, 0, RES_EXT_INT);
-	write_zsreg(info->zs_channel, 0, RES_EXT_INT);	/* to kill some time */
-
-	/* The channel should be OK now, but it is probably receiving
-	 * loopback garbage.
-	 * Switch to asynchronous mode, disable the receiver,
-	 * and discard everything in the receive buffer.
-	 */
-	write_zsreg(info->zs_channel, 9, NV);
-	write_zsreg(info->zs_channel, 4, PAR_ENA);
-	write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
-
-	while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) {
-		(void)read_zsreg(info->zs_channel, 8);
-		write_zsreg(info->zs_channel, 0, RES_EXT_INT);
-		write_zsreg(info->zs_channel, 0, ERR_RES);
-	}
-}
-
-static int setup_scc(struct mac_serial * info)
-{
-	unsigned long flags;
-
-	OPNDBG("setting up ttyS%d SCC...\n", info->line);
-
-	spin_lock_irqsave(&info->lock, flags);
-
-	/* Nice buggy HW ... */
-	fix_zero_bug_scc(info);
-
-	/*
-	 * Reset the chip.
-	 */
-	write_zsreg(info->zs_channel, 9,
-		    (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
-	udelay(10);
-	write_zsreg(info->zs_channel, 9, 0);
-
-	/*
-	 * Clear the receive FIFO.
-	 */
-	ZS_CLEARFIFO(info->zs_channel);
-	info->xmit_fifo_size = 1;
-
-	/*
-	 * Reset DMAs
-	 */
-	if (info->has_dma)
-		dma_init(info);
-
-	/*
-	 * Clear the interrupt registers.
-	 */
-	write_zsreg(info->zs_channel, 0, ERR_RES);
-	write_zsreg(info->zs_channel, 0, RES_H_IUS);
-
-	/*
-	 * Turn on RTS and DTR.
-	 */
-	if (!info->is_irda)
-		zs_rtsdtr(info, 1);
-
-	/*
-	 * Finally, enable sequencing and interrupts
-	 */
-	if (!info->dma_initted) {
-		/* interrupt on ext/status changes, all received chars,
-		   transmit ready */
-		info->curregs[1] = (info->curregs[1] & ~0x18)
-				| (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
-	} else {
-		/* interrupt on ext/status changes, W/Req pin is
-		   receive DMA request */
-		info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))
-				| (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
-		write_zsreg(info->zs_channel, 1, info->curregs[1]);
-		/* enable W/Req pin */
-		info->curregs[1] |= WT_RDY_ENAB;
-		write_zsreg(info->zs_channel, 1, info->curregs[1]);
-		/* enable interrupts on transmit ready and receive errors */
-		info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;
-	}
-	info->pendregs[1] = info->curregs[1];
-	info->curregs[3] |= (RxENABLE | Rx8);
-	info->pendregs[3] = info->curregs[3];
-	info->curregs[5] |= (TxENAB | Tx8);
-	info->pendregs[5] = info->curregs[5];
-	info->curregs[9] |= (NV | MIE);
-	info->pendregs[9] = info->curregs[9];
-	write_zsreg(info->zs_channel, 3, info->curregs[3]);
-	write_zsreg(info->zs_channel, 5, info->curregs[5]);
-	write_zsreg(info->zs_channel, 9, info->curregs[9]);
-
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-	spin_unlock_irqrestore(&info->lock, flags);
-
-	/*
-	 * Set the speed of the serial port
-	 */
-	change_speed(info, 0);
-
-	/* Save the current value of RR0 */
-	info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-
-	if (info->dma_initted) {
-		spin_lock_irqsave(&info->rx_dma_lock, flags);
-		rxdma_start(info, 0);
-		info->poll_dma_timer.expires = RX_DMA_TIMER;
-		add_timer(&info->poll_dma_timer);
-		spin_unlock_irqrestore(&info->rx_dma_lock, flags);
-	}
-
-	return 0;
-}
-
-/*
- * 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 mac_serial * info)
-{
-	OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line,
-	       info->irq);
-
-	if (!(info->flags & ZILOG_INITIALIZED)) {
-		OPNDBG("(already shutdown)\n");
-		return;
-	}
-
-	if (info->has_dma) {
-		del_timer(&info->poll_dma_timer);
-		dbdma_reset(info->tx_dma);
-		dbdma_reset(&info->rx->dma);
-		disable_irq(info->tx_dma_irq);
-		disable_irq(info->rx_dma_irq);
-	}
-	disable_irq(info->irq);
-
-	info->pendregs[1] = info->curregs[1] = 0;
-	write_zsreg(info->zs_channel, 1, 0);	/* no interrupts */
-
-	info->curregs[3] &= ~RxENABLE;
-	info->pendregs[3] = info->curregs[3];
-	write_zsreg(info->zs_channel, 3, info->curregs[3]);
-
-	info->curregs[5] &= ~TxENAB;
-	if (!info->tty || C_HUPCL(info->tty))
-		info->curregs[5] &= ~DTR;
-	info->pendregs[5] = info->curregs[5];
-	write_zsreg(info->zs_channel, 5, info->curregs[5]);
-
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-	set_scc_power(info, 0);
-
-	if (info->xmit_buf) {
-		free_page((unsigned long) info->xmit_buf);
-		info->xmit_buf = 0;
-	}
-
-	if (info->has_dma && info->dma_priv) {
-		kfree(info->dma_priv);
-		info->dma_priv = NULL;
-		info->dma_initted = 0;
-	}
-
-	memset(info->curregs, 0, sizeof(info->curregs));
-	memset(info->pendregs, 0, sizeof(info->pendregs));
-
-	info->flags &= ~ZILOG_INITIALIZED;
-}
-
-/*
- * Turn power on or off to the SCC and associated stuff
- * (port drivers, modem, IR port, etc.)
- * Returns the number of milliseconds we should wait before
- * trying to use the port.
- */
-static int set_scc_power(struct mac_serial * info, int state)
-{
-	int delay = 0;
-
-	if (state) {
-		PWRDBG("ttyS%d: powering up hardware\n", info->line);
-		pmac_call_feature(
-			PMAC_FTR_SCC_ENABLE,
-			info->dev_node, info->port_type, 1);
-		if (info->is_internal_modem) {
-			pmac_call_feature(
-				PMAC_FTR_MODEM_ENABLE,
-				info->dev_node, 0, 1);
-			delay = 2500;	/* wait for 2.5s before using */
-		} else if (info->is_irda)
-			mdelay(50);	/* Do better here once the problems
-			                 * with blocking have been ironed out
-			                 */
-	} else {
-		/* TODO: Make that depend on a timer, don't power down
-		 * immediately
-		 */
-		PWRDBG("ttyS%d: shutting down hardware\n", info->line);
-		if (info->is_internal_modem) {
-			PWRDBG("ttyS%d: shutting down modem\n", info->line);
-			pmac_call_feature(
-				PMAC_FTR_MODEM_ENABLE,
-				info->dev_node, 0, 0);
-		}
-		pmac_call_feature(
-			PMAC_FTR_SCC_ENABLE,
-			info->dev_node, info->port_type, 0);
-	}
-	return delay;
-}
-
-static void irda_rts_pulses(struct mac_serial *info, int w)
-{
-	udelay(w);
-	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
-	udelay(2);
-	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-	udelay(8);
-	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
-	udelay(4);
-	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-}
-
-/*
- * Set the irda codec on the imac to the specified baud rate.
- */
-static void irda_setup(struct mac_serial *info)
-{
-	int code, speed, t;
-
-	speed = info->tty->termios->c_cflag & CBAUD;
-	if (speed < B2400 || speed > B115200)
-		return;
-	code = 0x4d + B115200 - speed;
-
-	/* disable serial interrupts and receive DMA */
-	write_zsreg(info->zs_channel, 1, info->curregs[1] & ~0x9f);
-
-	/* wait for transmitter to drain */
-	t = 10000;
-	while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0
-	       || (read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
-		if (--t <= 0) {
-			printk(KERN_ERR "transmitter didn't drain\n");
-			return;
-		}
-		udelay(10);
-	}
-	udelay(100);
-
-	/* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */
-	write_zsreg(info->zs_channel, 4, X16CLK | SB1);
-	write_zsreg(info->zs_channel, 11, TCBR | RCBR);
-	t = BPS_TO_BRG(19200, ZS_CLOCK/16);
-	write_zsreg(info->zs_channel, 12, t);
-	write_zsreg(info->zs_channel, 13, t >> 8);
-	write_zsreg(info->zs_channel, 14, BRENABL);
-	write_zsreg(info->zs_channel, 3, Rx8 | RxENABLE);
-	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-
-	/* set TxD low for ~104us and pulse RTS */
-	udelay(1000);
-	write_zsdata(info->zs_channel, 0xfe);
-	irda_rts_pulses(info, 150);
-	irda_rts_pulses(info, 180);
-	irda_rts_pulses(info, 50);
-	udelay(100);
-
-	/* assert DTR, wait 30ms, talk to the chip */
-	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
-	mdelay(30);
-	while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
-		read_zsdata(info->zs_channel);
-
-	write_zsdata(info->zs_channel, 1);
-	t = 1000;
-	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
-		if (--t <= 0) {
-			printk(KERN_ERR "irda_setup timed out on 1st byte\n");
-			goto out;
-		}
-		udelay(10);
-	}
-	t = read_zsdata(info->zs_channel);
-	if (t != 4)
-		printk(KERN_ERR "irda_setup 1st byte = %x\n", t);
-
-	write_zsdata(info->zs_channel, code);
-	t = 1000;
-	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
-		if (--t <= 0) {
-			printk(KERN_ERR "irda_setup timed out on 2nd byte\n");
-			goto out;
-		}
-		udelay(10);
-	}
-	t = read_zsdata(info->zs_channel);
-	if (t != code)
-		printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code);
-
-	/* Drop DTR again and do some more RTS pulses */
- out:
-	udelay(100);
-	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-	irda_rts_pulses(info, 80);
-
-	/* We should be right to go now.  We assume that load_zsregs
-	   will get called soon to load up the correct baud rate etc. */
-	info->curregs[5] = (info->curregs[5] | RTS) & ~DTR;
-	info->pendregs[5] = info->curregs[5];
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct mac_serial *info, struct termios *old_termios)
-{
-	unsigned cflag;
-	int	bits;
-	int	brg, baud;
-	unsigned long flags;
-
-	if (!info->tty || !info->tty->termios)
-		return;
-
-	cflag = info->tty->termios->c_cflag;
-	baud = tty_get_baud_rate(info->tty);
-	if (baud == 0) {
-		if (old_termios) {
-			info->tty->termios->c_cflag &= ~CBAUD;
-			info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
-			cflag = info->tty->termios->c_cflag;
-			baud = tty_get_baud_rate(info->tty);
-		}
-		else
-			baud = info->zs_baud;
-	}
-	if (baud > 230400)
-		baud = 230400;
-	else if (baud == 0)
-		baud = 38400;
-
-	spin_lock_irqsave(&info->lock, flags);
-	info->zs_baud = baud;
-	info->clk_divisor = 16;
-
-	BAUDBG(KERN_DEBUG "set speed to %d bds, ", baud);
-
-	switch (baud) {
-	case ZS_CLOCK/16:	/* 230400 */
-		info->curregs[4] = X16CLK;
-		info->curregs[11] = 0;
-		break;
-	case ZS_CLOCK/32:	/* 115200 */
-		info->curregs[4] = X32CLK;
-		info->curregs[11] = 0;
-		break;
-	default:
-		info->curregs[4] = X16CLK;
-		info->curregs[11] = TCBR | RCBR;
-		brg = BPS_TO_BRG(baud, ZS_CLOCK/info->clk_divisor);
-		info->curregs[12] = (brg & 255);
-		info->curregs[13] = ((brg >> 8) & 255);
-		info->curregs[14] = BRENABL;
-	}
-
-	/* byte size and parity */
-	info->curregs[3] &= ~RxNBITS_MASK;
-	info->curregs[5] &= ~TxNBITS_MASK;
-	switch (cflag & CSIZE) {
-	case CS5:
-		info->curregs[3] |= Rx5;
-		info->curregs[5] |= Tx5;
-		BAUDBG("5 bits, ");
-		bits = 7;
-		break;
-	case CS6:
-		info->curregs[3] |= Rx6;
-		info->curregs[5] |= Tx6;
-		BAUDBG("6 bits, ");
-		bits = 8;
-		break;
-	case CS7:
-		info->curregs[3] |= Rx7;
-		info->curregs[5] |= Tx7;
-		BAUDBG("7 bits, ");
-		bits = 9;
-		break;
-	case CS8:
-	default: /* defaults to 8 bits */
-		info->curregs[3] |= Rx8;
-		info->curregs[5] |= Tx8;
-		BAUDBG("8 bits, ");
-		bits = 10;
-		break;
-	}
-	info->pendregs[3] = info->curregs[3];
-	info->pendregs[5] = info->curregs[5];
-
-	info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
-	if (cflag & CSTOPB) {
-		info->curregs[4] |= SB2;
-		bits++;
-		BAUDBG("2 stop, ");
-	} else {
-		info->curregs[4] |= SB1;
-		BAUDBG("1 stop, ");
-	}
-	if (cflag & PARENB) {
-		bits++;
- 		info->curregs[4] |= PAR_ENA;
-		BAUDBG("parity, ");
-	}
-	if (!(cflag & PARODD)) {
-		info->curregs[4] |= PAR_EVEN;
-	}
-	info->pendregs[4] = info->curregs[4];
-
-	if (!(cflag & CLOCAL)) {
-		if (!(info->curregs[15] & DCDIE))
-			info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-		info->curregs[15] |= DCDIE;
-	} else
-		info->curregs[15] &= ~DCDIE;
-	if (cflag & CRTSCTS) {
-		info->curregs[15] |= CTSIE;
-		if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
-			info->tx_stopped = 1;
-	} else {
-		info->curregs[15] &= ~CTSIE;
-		info->tx_stopped = 0;
-	}
-	info->pendregs[15] = info->curregs[15];
-
-	/* Calc timeout value. This is pretty broken with high baud rates with HZ=100.
-	   This code would love a larger HZ and a >1 fifo size, but this is not
-	   a priority. The resulting value must be >HZ/2
-	 */
-	info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud);
-	info->timeout += HZ/50+1;	/* Add .02 seconds of slop */
-
-	BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ,
-	       (int)info->baud_base);
-
-	/* set the irda codec to the right rate */
-	if (info->is_irda)
-		irda_setup(info);
-
-	/* Load up the new values */
-	load_zsregs(info->zs_channel, info->curregs);
-
-	spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
-		return;
-
-	spin_lock_irqsave(&info->lock, flags);
-	if (!(info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
-	      !info->xmit_buf))
-		/* Enable transmitter */
-		transmit_chars(info);
-	spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_write(struct tty_struct * tty,
-		    const unsigned char *buf, int count)
-{
-	int	c, ret = 0;
-	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_write"))
-		return 0;
-
-	if (!tty || !info->xmit_buf || !tmp_buf)
-		return 0;
-
-	while (1) {
-		spin_lock_irqsave(&info->lock, flags);
-		c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-					  SERIAL_XMIT_SIZE - info->xmit_head));
-		if (c <= 0) {
-			spin_unlock_irqrestore(&info->lock, 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;
-		spin_unlock_irqrestore(&info->lock, flags);
-		buf += c;
-		count -= c;
-		ret += c;
-	}
-	spin_lock_irqsave(&info->lock, flags);
-	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
-	    && !info->tx_active)
-		transmit_chars(info);
-	spin_unlock_irqrestore(&info->lock, flags);
-	return ret;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
-	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-	int	ret;
-
-	if (serial_paranoia_check(info, tty->name, "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 mac_serial *info = (struct mac_serial *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-		return 0;
-	return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
-	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-		return;
-	spin_lock_irqsave(&info->lock, flags);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	spin_unlock_irqrestore(&info->lock, flags);
-	tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * 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 mac_serial *info = (struct mac_serial *)tty->driver_data;
-	unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
-	printk(KERN_DEBUG "throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-		return;
-
-	if (I_IXOFF(tty)) {
-		spin_lock_irqsave(&info->lock, flags);
-		info->x_char = STOP_CHAR(tty);
-		if (!info->tx_active)
-			transmit_chars(info);
-		spin_unlock_irqrestore(&info->lock, flags);
-	}
-
-	if (C_CRTSCTS(tty)) {
-		/*
-		 * Here we want to turn off the RTS line.  On Macintoshes,
-		 * the external serial ports using a DIN-8 or DIN-9
-		 * connector only have the DTR line (which is usually
-		 * wired to both RTS and DTR on an external modem in
-		 * the cable).  RTS doesn't go out to the serial port
-		 * socket, it acts as an output enable for the transmit
-		 * data line.  So in this case we don't drop RTS.
-		 *
-		 * Macs with internal modems generally do have both RTS
-		 * and DTR wired to the modem, so in that case we do
-		 * drop RTS.
-		 */
-		if (info->is_internal_modem) {
-			spin_lock_irqsave(&info->lock, flags);
-			info->curregs[5] &= ~RTS;
-			info->pendregs[5] &= ~RTS;
-			write_zsreg(info->zs_channel, 5, info->curregs[5]);
-			spin_unlock_irqrestore(&info->lock, flags);
-		}
-	}
-	
-#ifdef CDTRCTS
-	if (tty->termios->c_cflag & CDTRCTS) {
-		spin_lock_irqsave(&info->lock, flags);
-		info->curregs[5] &= ~DTR;
-		info->pendregs[5] &= ~DTR;
-		write_zsreg(info->zs_channel, 5, info->curregs[5]);
-		spin_unlock_irqrestore(&info->lock, flags);
-	}
-#endif /* CDTRCTS */
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
-	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-	unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
-	printk(KERN_DEBUG "unthrottle %s: %d....\n",
-			tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-		return;
-
-	if (I_IXOFF(tty)) {
-		spin_lock_irqsave(&info->lock, flags);
-		if (info->x_char)
-			info->x_char = 0;
-		else {
-			info->x_char = START_CHAR(tty);
-			if (!info->tx_active)
-				transmit_chars(info);
-		}
-		spin_unlock_irqrestore(&info->lock, flags);
-	}
-
-	if (C_CRTSCTS(tty) && info->is_internal_modem) {
-		/* Assert RTS line */
-		spin_lock_irqsave(&info->lock, flags);
-		info->curregs[5] |= RTS;
-		info->pendregs[5] |= RTS;
-		write_zsreg(info->zs_channel, 5, info->curregs[5]);
-		spin_unlock_irqrestore(&info->lock, flags);
-	}
-
-#ifdef CDTRCTS
-	if (tty->termios->c_cflag & CDTRCTS) {
-		/* Assert DTR line */
-		spin_lock_irqsave(&info->lock, flags);
-		info->curregs[5] |= DTR;
-		info->pendregs[5] |= DTR;
-		write_zsreg(info->zs_channel, 5, info->curregs[5]);
-		spin_unlock_irqrestore(&info->lock, flags);
-	}
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct mac_serial * info,
-			   struct serial_struct __user * retinfo)
-{
-	struct serial_struct tmp;
-  
-	if (!retinfo)
-		return -EFAULT;
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.type = info->type;
-	tmp.line = info->line;
-	tmp.port = info->port;
-	tmp.irq = info->irq;
-	tmp.flags = info->flags;
-	tmp.baud_base = info->baud_base;
-	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
-	tmp.custom_divisor = info->custom_divisor;
-	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
-		return -EFAULT;
-	return 0;
-}
-
-static int set_serial_info(struct mac_serial * info,
-			   struct serial_struct __user * new_info)
-{
-	struct serial_struct new_serial;
-	struct mac_serial old_info;
-	int 			retval = 0;
-
-	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-		return -EFAULT;
-	old_info = *info;
-
-	if (!capable(CAP_SYS_ADMIN)) {
-		if ((new_serial.baud_base != info->baud_base) ||
-		    (new_serial.type != info->type) ||
-		    (new_serial.close_delay != info->close_delay) ||
-		    ((new_serial.flags & ~ZILOG_USR_MASK) !=
-		     (info->flags & ~ZILOG_USR_MASK)))
-			return -EPERM;
-		info->flags = ((info->flags & ~ZILOG_USR_MASK) |
-			       (new_serial.flags & ZILOG_USR_MASK));
-		info->custom_divisor = new_serial.custom_divisor;
-		goto check_and_exit;
-	}
-
-	if (info->count > 1)
-		return -EBUSY;
-
-	/*
-	 * OK, past this point, all the error checking has been done.
-	 * At this point, we start making changes.....
-	 */
-
-	info->baud_base = new_serial.baud_base;
-	info->flags = ((info->flags & ~ZILOG_FLAGS) |
-			(new_serial.flags & ZILOG_FLAGS));
-	info->type = new_serial.type;
-	info->close_delay = new_serial.close_delay;
-	info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
-	if (info->flags & ZILOG_INITIALIZED)
-		retval = setup_scc(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 mac_serial * info, unsigned int *value)
-{
-	unsigned char status;
-	unsigned long flags;
-
-	spin_lock_irqsave(&info->lock, flags);
-	status = read_zsreg(info->zs_channel, 0);
-	spin_unlock_irqrestore(&info->lock, flags);
-	status = (status & Tx_BUF_EMP)? TIOCSER_TEMT: 0;
-	return put_user(status,value);
-}
-
-static int rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-	unsigned char control, status;
-	unsigned long flags;
-
-#ifdef CONFIG_KGDB
-	if (info->kgdb_channel)
-		return -ENODEV;
-#endif
-	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
-		return -ENODEV;
-
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	spin_lock_irqsave(&info->lock, flags);
-	control = info->curregs[5];
-	status = read_zsreg(info->zs_channel, 0);
-	spin_unlock_irqrestore(&info->lock, flags);
-	return    ((control & RTS) ? TIOCM_RTS: 0)
-		| ((control & DTR) ? TIOCM_DTR: 0)
-		| ((status  & DCD) ? TIOCM_CAR: 0)
-		| ((status  & CTS) ? 0: TIOCM_CTS);
-}
-
-static int rs_tiocmset(struct tty_struct *tty, struct file *file,
-		       unsigned int set, unsigned int clear)
-{
-	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-	unsigned int arg, bits;
-	unsigned long flags;
-
-#ifdef CONFIG_KGDB
-	if (info->kgdb_channel)
-		return -ENODEV;
-#endif
-	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
-		return -ENODEV;
-
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	spin_lock_irqsave(&info->lock, flags);
-	if (set & TIOCM_RTS)
-		info->curregs[5] |= RTS;
-	if (set & TIOCM_DTR)
-		info->curregs[5] |= DTR;
-	if (clear & TIOCM_RTS)
-		info->curregs[5] &= ~RTS;
-	if (clear & TIOCM_DTR)
-		info->curregs[5] &= ~DTR;
-
-	info->pendregs[5] = info->curregs[5];
-	write_zsreg(info->zs_channel, 5, info->curregs[5]);
-	spin_unlock_irqrestore(&info->lock, flags);
-	return 0;
-}
-
-/*
- * rs_break - turn transmit break condition on/off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
-	struct mac_serial *info = (struct mac_serial *) tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_break"))
-		return;
-
-	spin_lock_irqsave(&info->lock, flags);
-	if (break_state == -1)
-		info->curregs[5] |= SND_BRK;
-	else
-		info->curregs[5] &= ~SND_BRK;
-	write_zsreg(info->zs_channel, 5, info->curregs[5]);
-	spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
-		    unsigned int cmd, unsigned long arg)
-{
-	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-
-#ifdef CONFIG_KGDB
-	if (info->kgdb_channel)
-		return -ENODEV;
-#endif
-	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-		return -ENODEV;
-
-	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
-		    return -EIO;
-	}
-
-	switch (cmd) {
-		case TIOCGSERIAL:
-			return get_serial_info(info,
-					(struct serial_struct __user *) arg);
-		case TIOCSSERIAL:
-			return set_serial_info(info,
-					(struct serial_struct __user *) arg);
-		case TIOCSERGETLSR: /* Get line status register */
-			return get_lsr_info(info, (unsigned int *) arg);
-
-		case TIOCSERGSTRUCT:
-			if (copy_to_user((struct mac_serial __user *) arg,
-					 info, sizeof(struct mac_serial)))
-				return -EFAULT;
-			return 0;
-
-		default:
-			return -ENOIOCTLCMD;
-		}
-	return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
-	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-	int was_stopped;
-
-	if (tty->termios->c_cflag == old_termios->c_cflag)
-		return;
-	was_stopped = info->tx_stopped;
-
-	change_speed(info, old_termios);
-
-	if (was_stopped && !info->tx_stopped) {
-		tty->hw_stopped = 0;
-		rs_start(tty);
-	}
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- * 
- * This routine is called when the serial port gets closed.
- * Wait for the last remaining data to be sent.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
-	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-		return;
-
-	spin_lock_irqsave(&info->lock, flags);
-
-	if (tty_hung_up_p(filp)) {
-		spin_unlock_irqrestore(&info->lock, flags);
-		return;
-	}
-
-	OPNDBG("rs_close ttyS%d, count = %d\n", info->line, info->count);
-	if ((tty->count == 1) && (info->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  Info->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(KERN_ERR "rs_close: bad serial port count; tty->count "
-				"is 1, info->count is %d\n", info->count);
-		info->count = 1;
-	}
-	if (--info->count < 0) {
-		printk(KERN_ERR "rs_close: bad serial port count for "
-				"ttyS%d: %d\n", info->line, info->count);
-		info->count = 0;
-	}
-	if (info->count) {
-		spin_unlock_irqrestore(&info->lock, flags);
-		return;
-	}
-	info->flags |= ZILOG_CLOSING;
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
-	tty->closing = 1;
-	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
-		spin_unlock_irqrestore(&info->lock, flags);
-		tty_wait_until_sent(tty, info->closing_wait);
-		spin_lock_irqsave(&info->lock, flags);
-	}
-
-	/*
-	 * At this point we stop accepting input.  To do this, we
-	 * disable the receiver and receive interrupts.
-	 */
-	info->curregs[3] &= ~RxENABLE;
-	info->pendregs[3] = info->curregs[3];
-	write_zsreg(info->zs_channel, 3, info->curregs[3]);
-	info->curregs[1] &= ~(0x18);	/* disable any rx ints */
-	info->pendregs[1] = info->curregs[1];
-	write_zsreg(info->zs_channel, 1, info->curregs[1]);
-	ZS_CLEARFIFO(info->zs_channel);
-	if (info->flags & ZILOG_INITIALIZED) {
-		/*
-		 * Before we drop DTR, make sure the SCC transmitter
-		 * has completely drained.
-		 */
-		OPNDBG("waiting end of Rx...\n");
-		spin_unlock_irqrestore(&info->lock, flags);
-		rs_wait_until_sent(tty, info->timeout);
-		spin_lock_irqsave(&info->lock, flags);
-	}
-
-	shutdown(info);
-	/* restore flags now since shutdown() will have disabled this port's
-	   specific irqs */
-	spin_unlock_irqrestore(&info->lock, flags);
-
-	if (tty->driver->flush_buffer)
-		tty->driver->flush_buffer(tty);
-	tty_ldisc_flush(tty);
-	tty->closing = 0;
-	info->event = 0;
-	info->tty = 0;
-
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
-		}
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
-	wake_up_interruptible(&info->close_wait);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-	struct mac_serial *info = (struct mac_serial *) tty->driver_data;
-	unsigned long orig_jiffies, char_time;
-
-	if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-		return;
-
-/*	printk("rs_wait_until_sent, timeout:%d, tty_stopped:%d, tx_stopped:%d\n",
-			timeout, tty->stopped, info->tx_stopped);
-*/
-	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.
-	 */
-	if (info->timeout <= HZ/50) {
-		printk(KERN_INFO "macserial: invalid info->timeout=%d\n",
-				    info->timeout);
-		info->timeout = HZ/50+1;
-	}
-
-	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
-	char_time = char_time / 5;
-	if (char_time > HZ) {
-		printk(KERN_WARNING "macserial: char_time %ld >HZ !!!\n",
-				    char_time);
-		char_time = 1;
-	} else if (char_time == 0)
-		char_time = 1;
-	if (timeout)
-		char_time = min_t(unsigned long, char_time, timeout);
-	while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
-		msleep_interruptible(jiffies_to_msecs(char_time));
-		if (signal_pending(current))
-			break;
-		if (timeout && time_after(jiffies, orig_jiffies + timeout))
-			break;
-	}
-	current->state = TASK_RUNNING;
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_hangup(struct tty_struct *tty)
-{
-	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-		return;
-
-	rs_flush_buffer(tty);
-	shutdown(info);
-	info->event = 0;
-	info->count = 0;
-	info->flags &= ~ZILOG_NORMAL_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 mac_serial *info)
-{
-	DECLARE_WAITQUEUE(wait,current);
-	int		retval;
-	int		do_clocal = 0;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (info->flags & ZILOG_CLOSING) {
-		interruptible_sleep_on(&info->close_wait);
-		return -EAGAIN;
-	}
-
-	/*
-	 * 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))) {
-		info->flags |= ZILOG_NORMAL_ACTIVE;
-		return 0;
-	}
-
-	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, info->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);
-	OPNDBG("block_til_ready before block: ttyS%d, count = %d\n",
-	       info->line, info->count);
-	spin_lock_irq(&info->lock);
-	if (!tty_hung_up_p(filp)) 
-		info->count--;
-	spin_unlock_irq(&info->lock);
-	info->blocked_open++;
-	while (1) {
-		spin_lock_irq(&info->lock);
-		if ((tty->termios->c_cflag & CBAUD) &&
-		    !info->is_irda)
-			zs_rtsdtr(info, 1);
-		spin_unlock_irq(&info->lock);
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ZILOG_INITIALIZED)) {
-			retval = -EAGAIN;
-			break;
-		}
-		if (!(info->flags & ZILOG_CLOSING) &&
-		    (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
-			break;
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-		OPNDBG("block_til_ready blocking: ttyS%d, count = %d\n",
-		       info->line, info->count);
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-	OPNDBG("block_til_ready after blocking: ttyS%d, count = %d\n",
-	       info->line, info->count);
-	if (retval)
-		return retval;
-	info->flags |= ZILOG_NORMAL_ACTIVE;
-	return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its ZILOG 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 mac_serial	*info;
-	int 			retval, line;
-	unsigned long		page;
-
-	line = tty->index;
-	if ((line < 0) || (line >= zs_channels_found)) {
-		return -ENODEV;
-	}
-	info = zs_soft + line;
-
-#ifdef CONFIG_KGDB
-	if (info->kgdb_channel) {
-		return -ENODEV;
-	}
-#endif
-	if (serial_paranoia_check(info, tty->name, "rs_open"))
-		return -ENODEV;
-	OPNDBG("rs_open %s, count = %d, tty=%p\n", tty->name,
-	       info->count, tty);
-
-	info->count++;
-	tty->driver_data = info;
-	info->tty = tty;
-
-	if (!tmp_buf) {
-		page = get_zeroed_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 & ZILOG_CLOSING)) {
-		if (info->flags & ZILOG_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-		return -EAGAIN;
-	}
-
-	/*
-	 * Start up serial port
-	 */
-
-	retval = startup(info);
-	if (retval)
-		return retval;
-
-	retval = block_til_ready(tty, filp, info);
-	if (retval) {
-		OPNDBG("rs_open returning after block_til_ready with %d\n",
-			retval);
-		return retval;
-	}
-
-#ifdef CONFIG_SERIAL_CONSOLE
-	if (sercons.cflag && sercons.index == line) {
-		tty->termios->c_cflag = sercons.cflag;
-		sercons.cflag = 0;
-		change_speed(info, 0);
-	}
-#endif
-
-	OPNDBG("rs_open %s successful...\n", tty->name);
-	return 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-	printk(KERN_INFO "PowerMac Z8530 serial driver version " MACSERIAL_VERSION "\n");
-}
-
-/*
- * Initialize one channel, both the mac_serial and mac_zschannel
- * structs.  We use the dev_node field of the mac_serial struct.
- */
-static int
-chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
-	  struct mac_zschannel *zs_chan_a)
-{
-	struct device_node *ch = zss->dev_node;
-	char *conn;
-	int len;
-	struct slot_names_prop {
-		int	count;
-		char	name[1];
-	} *slots;
-
-	zss->irq = ch->intrs[0].line;
-	zss->has_dma = 0;
-#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
-	if (ch->n_addrs >= 3 && ch->n_intrs == 3)
-		zss->has_dma = 1;
-#endif
-	zss->dma_initted = 0;
-
-	zs_chan->control = (volatile unsigned char *)
-		ioremap(ch->addrs[0].address, 0x1000);
-	zs_chan->data = zs_chan->control + 0x10;
-	spin_lock_init(&zs_chan->lock);
-	zs_chan->parent = zss;
-	zss->zs_channel = zs_chan;
-	zss->zs_chan_a = zs_chan_a;
-
-	/* setup misc varariables */
-	zss->kgdb_channel = 0;
-
-	/* For now, we assume you either have a slot-names property
-	 * with "Modem" in it, or your channel is compatible with
-	 * "cobalt". Might need additional fixups
-	 */
-	zss->is_internal_modem = device_is_compatible(ch, "cobalt");
-	conn = get_property(ch, "AAPL,connector", &len);
-	zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
-	zss->port_type = PMAC_SCC_ASYNC;
-	/* 1999 Powerbook G3 has slot-names property instead */
-	slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
-	if (slots && slots->count > 0) {
-		if (strcmp(slots->name, "IrDA") == 0)
-			zss->is_irda = 1;
-		else if (strcmp(slots->name, "Modem") == 0)
-			zss->is_internal_modem = 1;
-	}
-	if (zss->is_irda)
-		zss->port_type = PMAC_SCC_IRDA;
-	if (zss->is_internal_modem) {
-		struct device_node* i2c_modem = find_devices("i2c-modem");
-		if (i2c_modem) {
-			char* mid = get_property(i2c_modem, "modem-id", NULL);
-			if (mid) switch(*mid) {
-			case 0x04 :
-			case 0x05 :
-			case 0x07 :
-			case 0x08 :
-			case 0x0b :
-			case 0x0c :
-				zss->port_type = PMAC_SCC_I2S1;
-			}
-			printk(KERN_INFO "macserial: i2c-modem detected, id: %d\n",
-				mid ? (*mid) : 0);
-		} else {
-			printk(KERN_INFO "macserial: serial modem detected\n");
-		}
-	}
-
-	while (zss->has_dma) {
-		zss->dma_priv = NULL;
-		/* it seems that the last two addresses are the
-		   DMA controllers */
-		zss->tx_dma = (volatile struct dbdma_regs *)
-			ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100);
-		zss->rx = (volatile struct mac_dma *)
-			ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100);
-		zss->tx_dma_irq = ch->intrs[1].line;
-		zss->rx_dma_irq = ch->intrs[2].line;
-		spin_lock_init(&zss->rx_dma_lock);
-		break;
-	}
-
-	init_timer(&zss->powerup_timer);
-	zss->powerup_timer.function = powerup_done;
-	zss->powerup_timer.data = (unsigned long) zss;
-	return 0;
-}
-
-/*
- * /proc fs routines. TODO: Add status lines & error stats
- */
-static inline int
-line_info(char *buf, struct mac_serial *info)
-{
-	int		ret=0;
-	unsigned char* connector;
-	int lenp;
-
-	ret += sprintf(buf, "%d: port:0x%X irq:%d", info->line, info->port, info->irq);
-
-	connector = get_property(info->dev_node, "AAPL,connector", &lenp);
-	if (connector)
-		ret+=sprintf(buf+ret," con:%s ", connector);
-	if (info->is_internal_modem) {
-		if (!connector)
-			ret+=sprintf(buf+ret," con:");
-		ret+=sprintf(buf+ret,"%s", " (internal modem)");
-	}
-	if (info->is_irda) {
-		if (!connector)
-			ret+=sprintf(buf+ret," con:");
-		ret+=sprintf(buf+ret,"%s", " (IrDA)");
-	}
-	ret+=sprintf(buf+ret,"\n");
-
-	return ret;
-}
-
-int macserial_read_proc(char *page, char **start, off_t off, int count,
-		 int *eof, void *data)
-{
-	int l, len = 0;
-	off_t	begin = 0;
-	struct mac_serial *info;
-
-	len += sprintf(page, "serinfo:1.0 driver:" MACSERIAL_VERSION "\n");
-	for (info = zs_chain; info && len < 4000; info = info->zs_next) {
-		l = line_info(page + len, info);
-		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 + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
-static void
-probe_sccs(void)
-{
-	struct device_node *dev, *ch;
-	struct mac_serial **pp;
-	int n, chip, nchan;
-	struct mac_zschannel *zs_chan;
-	int chan_a_index;
-
-	n = 0;
-	pp = &zs_chain;
-	zs_chan = zs_channels;
-	for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
-		nchan = 0;
-		chip = n;
-		if (n >= NUM_CHANNELS) {
-			printk(KERN_WARNING "Sorry, can't use %s: no more "
-					    "channels\n", dev->full_name);
-			continue;
-		}
-		chan_a_index = 0;
-		for (ch = dev->child; ch != 0; ch = ch->sibling) {
-			if (nchan >= 2) {
-				printk(KERN_WARNING "SCC: Only 2 channels per "
-					"chip are supported\n");
-				break;
-			}
-			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;
-			}
-
-			/* The channel with the higher address
-			   will be the A side. */
-			if (nchan > 0 &&
-			    ch->addrs[0].address
-			    > zs_soft[n-1].dev_node->addrs[0].address)
-				chan_a_index = 1;
-
-			/* minimal initialization for now */
-			zs_soft[n].dev_node = ch;
-			*pp = &zs_soft[n];
-			pp = &zs_soft[n].zs_next;
-			++nchan;
-			++n;
-		}
-		if (nchan == 0)
-			continue;
-
-		/* set up A side */
-		if (chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan))
-			continue;
-		++zs_chan;
-
-		/* set up B side, if it exists */
-		if (nchan > 1)
-			if (chan_init(&zs_soft[chip + 1 - chan_a_index],
-				  zs_chan, zs_chan - 1))
-				continue;
-		++zs_chan;
-	}
-	*pp = 0;
-
-	zs_channels_found = n;
-#ifdef CONFIG_PMAC_PBOOK
-	if (n)
-		pmu_register_sleep_notifier(&serial_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-}
-
-static struct tty_operations serial_ops = {
-	.open = rs_open,
-	.close = rs_close,
-	.write = rs_write,
-	.flush_chars = rs_flush_chars,
-	.write_room = rs_write_room,
-	.chars_in_buffer = rs_chars_in_buffer,
-	.flush_buffer = rs_flush_buffer,
-	.ioctl = rs_ioctl,
-	.throttle = rs_throttle,
-	.unthrottle = rs_unthrottle,
-	.set_termios = rs_set_termios,
-	.stop = rs_stop,
-	.start = rs_start,
-	.hangup = rs_hangup,
-	.break_ctl = rs_break,
-	.wait_until_sent = rs_wait_until_sent,
-	.read_proc = macserial_read_proc,
-	.tiocmget = rs_tiocmget,
-	.tiocmset = rs_tiocmset,
-};
-
-static int macserial_init(void)
-{
-	int channel, i;
-	struct mac_serial *info;
-
-	/* Find out how many Z8530 SCCs we have */
-	if (zs_chain == 0)
-		probe_sccs();
-
-	serial_driver = alloc_tty_driver(zs_channels_found);
-	if (!serial_driver)
-		return -ENOMEM;
-
-	/* XXX assume it's a powerbook if we have a via-pmu
-	 * 
-	 * This is OK for core99 machines as well.
-	 */
-	is_powerbook = find_devices("via-pmu") != 0;
-
-	/* Register the interrupt handler for each one
-	 * We also request the OF resources here as probe_sccs()
-	 * might be called too early for that
-	 */
-	for (i = 0; i < zs_channels_found; ++i) {
-		struct device_node* ch = zs_soft[i].dev_node;
-		if (!request_OF_resource(ch, 0, NULL)) {
-			printk(KERN_ERR "macserial: can't request IO resource !\n");
-			put_tty_driver(serial_driver);
-			return -ENODEV;
-		}
-		if (zs_soft[i].has_dma) {
-			if (!request_OF_resource(ch, ch->n_addrs - 2, " (tx dma)")) {
-				printk(KERN_ERR "macserial: can't request TX DMA resource !\n");
-				zs_soft[i].has_dma = 0;
-				goto no_dma;
-			}
-			if (!request_OF_resource(ch, ch->n_addrs - 1, " (rx dma)")) {
-				release_OF_resource(ch, ch->n_addrs - 2);
-				printk(KERN_ERR "macserial: can't request RX DMA resource !\n");
-				zs_soft[i].has_dma = 0;
-				goto no_dma;
-			}
-			if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0,
-					"SCC-txdma", &zs_soft[i]))
-				printk(KERN_ERR "macserial: can't get irq %d\n",
-				       zs_soft[i].tx_dma_irq);
-			disable_irq(zs_soft[i].tx_dma_irq);
-			if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0,
-					"SCC-rxdma", &zs_soft[i]))
-				printk(KERN_ERR "macserial: can't get irq %d\n",
-				       zs_soft[i].rx_dma_irq);
-			disable_irq(zs_soft[i].rx_dma_irq);
-		}
-no_dma:		
-		if (request_irq(zs_soft[i].irq, rs_interrupt, 0,
-				"SCC", &zs_soft[i]))
-			printk(KERN_ERR "macserial: can't get irq %d\n",
-			       zs_soft[i].irq);
-		disable_irq(zs_soft[i].irq);
-	}
-
-	show_serial_version();
-
-	/* Initialize the tty_driver structure */
-	/* Not all of this is exactly right for us. */
-
-	serial_driver->owner = THIS_MODULE;
-	serial_driver->driver_name = "macserial";
-	serial_driver->devfs_name = "tts/";
-	serial_driver->name = "ttyS";
-	serial_driver->major = TTY_MAJOR;
-	serial_driver->minor_start = 64;
-	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 =
-		B38400 | CS8 | CREAD | HUPCL | CLOCAL;
-	serial_driver->flags = TTY_DRIVER_REAL_RAW;
-	tty_set_operations(serial_driver, &serial_ops);
-
-	if (tty_register_driver(serial_driver))
-		printk(KERN_ERR "Error: couldn't register serial driver\n");
-
-	for (channel = 0; channel < zs_channels_found; ++channel) {
-#ifdef CONFIG_KGDB
-		if (zs_soft[channel].kgdb_channel) {
-			kgdb_interruptible(1);
-			continue;
-		}
-#endif
-		zs_soft[channel].clk_divisor = 16;
-/* -- we are not sure the SCC is powered ON at this point
- 		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-*/
-		zs_soft[channel].zs_baud = 38400;
-
-		/* If console serial line, then enable interrupts. */
-		if (zs_soft[channel].is_cons) {
-			printk(KERN_INFO "macserial: console line, enabling "
-					"interrupt %d\n", zs_soft[channel].irq);
-			panic("macserial: console not supported yet !");
-			write_zsreg(zs_soft[channel].zs_channel, R1,
-				    (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
-			write_zsreg(zs_soft[channel].zs_channel, R9,
-				    (NV | MIE));
-		}
-	}
-
-	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
-	{
-		unsigned char* connector;
-		int lenp;
-
-#ifdef CONFIG_KGDB
-		if (info->kgdb_channel) {
-			continue;
-		}
-#endif
-		info->magic = SERIAL_MAGIC;
-		info->port = (int) info->zs_channel->control;
-		info->line = i;
-		info->tty = 0;
-		info->custom_divisor = 16;
-		info->timeout = 0;
-		info->close_delay = 50;
-		info->closing_wait = 3000;
-		info->x_char = 0;
-		info->event = 0;
-		info->count = 0;
-		info->blocked_open = 0;
-		INIT_WORK(&info->tqueue, do_softint, info);
-		spin_lock_init(&info->lock);
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
-		info->timeout = HZ;
-		printk(KERN_INFO "tty%02d at 0x%08x (irq = %d)", info->line, 
-			info->port, info->irq);
-		printk(" is a Z8530 ESCC");
-		connector = get_property(info->dev_node, "AAPL,connector", &lenp);
-		if (connector)
-			printk(", port = %s", connector);
-		if (info->is_internal_modem)
-			printk(" (internal modem)");
-		if (info->is_irda)
-			printk(" (IrDA)");
-		printk("\n");
- 	}
-	tmp_buf = 0;
-
-	return 0;
-}
-
-void macserial_cleanup(void)
-{
-	int i;
-	unsigned long flags;
-	struct mac_serial *info;
-
-	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
-		set_scc_power(info, 0);
-	spin_lock_irqsave(&info->lock, flags);
-	for (i = 0; i < zs_channels_found; ++i) {
-		free_irq(zs_soft[i].irq, &zs_soft[i]);
-		if (zs_soft[i].has_dma) {
-			free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]);
-			free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]);
-		}
-		release_OF_resource(zs_soft[i].dev_node, 0);
-		if (zs_soft[i].has_dma) {
-			struct device_node* ch = zs_soft[i].dev_node;
-			release_OF_resource(ch, ch->n_addrs - 2);
-			release_OF_resource(ch, ch->n_addrs - 1);
-		}
-	}
-	spin_unlock_irqrestore(&info->lock, flags);
-	tty_unregister_driver(serial_driver);
-	put_tty_driver(serial_driver);
-
-	if (tmp_buf) {
-		free_page((unsigned long) tmp_buf);
-		tmp_buf = 0;
-	}
-
-#ifdef CONFIG_PMAC_PBOOK
-	if (zs_channels_found)
-		pmu_unregister_sleep_notifier(&serial_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-}
-
-module_init(macserial_init);
-module_exit(macserial_cleanup);
-MODULE_LICENSE("GPL");
-
-#if 0
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* PowerMac: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
-	return -1;
-}
-
-void unregister_serial(int line)
-{
-	return;
-}
-#endif
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- *	Print a string to the serial port trying not to disturb
- *	any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
-				 unsigned count)
-{
-	struct mac_serial *info = zs_soft + co->index;
-	int i;
-
-	/* Turn of interrupts and enable the transmitter. */
-	write_zsreg(info->zs_channel, R1, info->curregs[1] & ~TxINT_ENAB);
-	write_zsreg(info->zs_channel, R5, info->curregs[5] | TxENAB | RTS | DTR);
-
-	for (i=0; i<count; i++) {
-		/* Wait for the transmit buffer to empty. */
-		while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) {
-			eieio();
-		}
-
-		write_zsdata(info->zs_channel, s[i]);
-		if (s[i] == 10) {
-			while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
-                                == 0)
-				eieio();
-
-			write_zsdata(info->zs_channel, 13);
-		}
-	}
-
-	/* Restore the values in the registers. */
-	write_zsreg(info->zs_channel, R1, info->curregs[1]);
-	/* Don't disable the transmitter. */
-}
-
-static struct tty_driver *serial_driver;
-
-static struct tty_driver *serial_console_device(struct console *c, int *index)
-{
-	*index = c->index;
-	return serial_driver;
-}
-
-/*
- *	Setup initial baud/bits/parity. We do two things here:
- *	- construct a cflag setting for the first rs_open()
- *	- initialize the serial port
- *	Return non-zero if we didn't find a serial port.
- */
-static int __init serial_console_setup(struct console *co, char *options)
-{
-	struct mac_serial *info;
-	int	baud = 38400;
-	int	bits = 8;
-	int	parity = 'n';
-	int	cflag = CREAD | HUPCL | CLOCAL;
-	int	brg;
-	char	*s;
-	long	flags;
-
-	/* Find out how many Z8530 SCCs we have */
-	if (zs_chain == 0)
-		probe_sccs();
-
-	if (zs_chain == 0)
-		return -1;
-
-	/* Do we have the device asked for? */
-	if (co->index >= zs_channels_found)
-		return -1;
-	info = zs_soft + co->index;
-
-	set_scc_power(info, 1);
-
-	/* Reset the channel */
-	write_zsreg(info->zs_channel, R9, CHRA);
-
-	if (options) {
-		baud = simple_strtoul(options, NULL, 10);
-		s = options;
-		while(*s >= '0' && *s <= '9')
-			s++;
-		if (*s)
-			parity = *s++;
-		if (*s)
-			bits   = *s - '0';
-	}
-
-	/*
-	 *	Now construct a cflag setting.
-	 */
-	switch(baud) {
-	case 1200:
-		cflag |= B1200;
-		break;
-	case 2400:
-		cflag |= B2400;
-		break;
-	case 4800:
-		cflag |= B4800;
-		break;
-	case 9600:
-		cflag |= B9600;
-		break;
-	case 19200:
-		cflag |= B19200;
-		break;
-	case 57600:
-		cflag |= B57600;
-		break;
-	case 115200:
-		cflag |= B115200;
-		break;
-	case 38400:
-	default:
-		cflag |= B38400;
-		break;
-	}
-	switch(bits) {
-	case 7:
-		cflag |= CS7;
-		break;
-	default:
-	case 8:
-		cflag |= CS8;
-		break;
-	}
-	switch(parity) {
-	case 'o': case 'O':
-		cflag |= PARENB | PARODD;
-		break;
-	case 'e': case 'E':
-		cflag |= PARENB;
-		break;
-	}
-	co->cflag = cflag;
-
-	spin_lock_irqsave(&info->lock, flags);
-        memset(info->curregs, 0, sizeof(info->curregs));
-
-	info->zs_baud = baud;
-	info->clk_divisor = 16;
-	switch (info->zs_baud) {
-	case ZS_CLOCK/16:	/* 230400 */
-		info->curregs[4] = X16CLK;
-		info->curregs[11] = 0;
-		break;
-	case ZS_CLOCK/32:	/* 115200 */
-		info->curregs[4] = X32CLK;
-		info->curregs[11] = 0;
-		break;
-	default:
-		info->curregs[4] = X16CLK;
-		info->curregs[11] = TCBR | RCBR;
-		brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
-		info->curregs[12] = (brg & 255);
-		info->curregs[13] = ((brg >> 8) & 255);
-		info->curregs[14] = BRENABL;
-	}
-
-	/* byte size and parity */
-	info->curregs[3] &= ~RxNBITS_MASK;
-	info->curregs[5] &= ~TxNBITS_MASK;
-	switch (cflag & CSIZE) {
-	case CS5:
-		info->curregs[3] |= Rx5;
-		info->curregs[5] |= Tx5;
-		break;
-	case CS6:
-		info->curregs[3] |= Rx6;
-		info->curregs[5] |= Tx6;
-		break;
-	case CS7:
-		info->curregs[3] |= Rx7;
-		info->curregs[5] |= Tx7;
-		break;
-	case CS8:
-	default: /* defaults to 8 bits */
-		info->curregs[3] |= Rx8;
-		info->curregs[5] |= Tx8;
-		break;
-	}
-        info->curregs[5] |= TxENAB | RTS | DTR;
-	info->pendregs[3] = info->curregs[3];
-	info->pendregs[5] = info->curregs[5];
-
-	info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
-	if (cflag & CSTOPB) {
-		info->curregs[4] |= SB2;
-	} else {
-		info->curregs[4] |= SB1;
-	}
-	if (cflag & PARENB) {
-		info->curregs[4] |= PAR_ENA;
-		if (!(cflag & PARODD)) {
-			info->curregs[4] |= PAR_EVEN;
-		}
-	}
-	info->pendregs[4] = info->curregs[4];
-
-	if (!(cflag & CLOCAL)) {
-		if (!(info->curregs[15] & DCDIE))
-			info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-		info->curregs[15] |= DCDIE;
-	} else
-		info->curregs[15] &= ~DCDIE;
-	if (cflag & CRTSCTS) {
-		info->curregs[15] |= CTSIE;
-		if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
-			info->tx_stopped = 1;
-	} else {
-		info->curregs[15] &= ~CTSIE;
-		info->tx_stopped = 0;
-	}
-	info->pendregs[15] = info->curregs[15];
-
-	/* Load up the new values */
-	load_zsregs(info->zs_channel, info->curregs);
-
-	spin_unlock_irqrestore(&info->lock, flags);
-
-	return 0;
-}
-
-static struct console sercons = {
-	.name		= "ttyS",
-	.write		= serial_console_write,
-	.device		= serial_console_device,
-	.setup		= serial_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-};
-
-/*
- *	Register console.
- */
-static void __init mac_scc_console_init(void)
-{
-	register_console(&sercons);
-}
-console_initcall(mac_scc_console_init);
-
-#endif /* ifdef CONFIG_SERIAL_CONSOLE */
-
-#ifdef CONFIG_KGDB
-/* 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)
-		eieio(); /*barrier();*/
-	return read_zsdata(chan);
-}
-
-void kgdb_interruptible(int yes)
-{
-	struct mac_zschannel *chan = zs_kgdbchan;
-	int one, nine;
-	nine = read_zsreg(chan, 9);
-	if (yes == 1) {
-		one = EXT_INT_ENAB|INT_ALL_Rx;
-		nine |= MIE;
-		printk("turning serial ints on\n");
-	} else {
-		one = RxINT_DISAB;
-		nine &= ~MIE;
-		printk("turning serial ints off\n");
-	}
-	write_zsreg(chan, 1, one);
-	write_zsreg(chan, 9, nine);
-}
-
-/* This sets up the serial port we're using, and turns on
- * interrupts for that channel, so kgdb is usable once we're done.
- */
-static inline void kgdb_chaninit(struct mac_zschannel *ms, int intson, int bps)
-{
-	int brg;
-	int i, x;
-	volatile char *sccc = ms->control;
-	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
-	printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
-	for (i = 20000; i != 0; --i) {
-		x = *sccc; eieio();
-	}
-	for (i = 0; i < sizeof(scc_inittab); ++i) {
-		write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
-		i++;
-	}
-}
-
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line.  The 'tty_num' argument is 0 for /dev/ttya and 1
- * for /dev/ttyb which is determined in setup_arch() from the
- * boot command line flags.
- * XXX at the moment probably only channel A will work
- */
-void __init zs_kgdb_hook(int tty_num)
-{
-	/* Find out how many Z8530 SCCs we have */
-	if (zs_chain == 0)
-		probe_sccs();
-
-	set_scc_power(&zs_soft[tty_num], 1);
-
-	zs_kgdbchan = zs_soft[tty_num].zs_channel;
-	zs_soft[tty_num].change_needed = 0;
-	zs_soft[tty_num].clk_divisor = 16;
-	zs_soft[tty_num].zs_baud = 38400;
-	zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
-
-	/* Turn on transmitter/receiver at 8-bits/char */
-        kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
-	printk("KGDB: on channel %d initialized\n", tty_num);
-	set_debug_traps(); /* init stub */
-}
-#endif /* ifdef CONFIG_KGDB */
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * notify clients before sleep and reset bus afterwards
- */
-int
-serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
-	int i;
-
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-	case PBOOK_SLEEP_REJECT:
-		break;
-
-	case PBOOK_SLEEP_NOW:
-		for (i=0; i<zs_channels_found; i++) {
-			struct mac_serial *info = &zs_soft[i];
-			if (info->flags & ZILOG_INITIALIZED) {
-				shutdown(info);
-				info->flags |= ZILOG_SLEEPING;
-			}
-		}
-		break;
-	case PBOOK_WAKE:
-		for (i=0; i<zs_channels_found; i++) {
-			struct mac_serial *info = &zs_soft[i];
-			if (info->flags & ZILOG_SLEEPING) {
-				info->flags &= ~ZILOG_SLEEPING;
-				startup(info);
-			}
-		}
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h
deleted file mode 100644
index bade11a..0000000
--- a/drivers/macintosh/macserial.h
+++ /dev/null
@@ -1,461 +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 _MACSERIAL_H
-#define _MACSERIAL_H
-
-#include <linux/spinlock.h>
-
-#define NUM_ZSREGS    16
-
-struct serial_struct {
-	int	type;
-	int	line;
-	int	port;
-	int	irq;
-	int	flags;
-	int	xmit_fifo_size;
-	int	custom_divisor;
-	int	baud_base;
-	unsigned short	close_delay;
-	char	reserved_char[2];
-	int	hub6;
-	unsigned short	closing_wait; /* time to wait before closing */
-	unsigned short	closing_wait2; /* no longer used... */
-	int	reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define 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 */
-#define ZILOG_SLEEPING		0x01000000 /* have shut it down for sleep */
-
-/* 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
- */
-
-struct mac_serial;
-
-struct mac_zschannel {
-	volatile unsigned char*	control;
-	volatile unsigned char*	data;
-	spinlock_t		lock;
-	/* Used for debugging */
-	struct mac_serial*	parent;
-};
-
-struct mac_dma {
-	volatile struct dbdma_regs	dma;
-	volatile unsigned short		res_count;
-	volatile unsigned short		command;
-	volatile unsigned int		buf_addr;
-};
-
-struct mac_serial {
-	struct mac_serial *zs_next;	/* For IRQ servicing chain */
-	struct mac_zschannel *zs_channel; /* Channel registers */
-	struct mac_zschannel *zs_chan_a;	/* A side registers */
-	unsigned char read_reg_zero;
-	struct device_node* dev_node;
-	spinlock_t lock;
-
-	char soft_carrier;  /* Use soft carrier on this channel */
-	char break_abort;   /* Is serial console in, so process brk/abrt */
-	char kgdb_channel;  /* Kgdb is running on this channel */
-	char is_cons;       /* Is this our console. */
-	char is_internal_modem; /* is connected to an internal modem */
-	char is_irda;		/* is connected to an IrDA codec */
-	int port_type;		/* Port type for pmac_feature */
-	unsigned char tx_active; /* character is being xmitted */
-	unsigned char tx_stopped; /* output is suspended */
-	unsigned char power_wait; /* waiting for power-up delay to expire */
-
-	/* We need to know the current clock divisor
-	 * to read the bps rate the chip has currently
-	 * loaded.
-	 */
-	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
-	int zs_baud;
-
-	/* Current write register values */
-	unsigned char curregs[NUM_ZSREGS];
-
-	/* Values we need to set next opportunity */
-	unsigned char pendregs[NUM_ZSREGS];
-
-	char change_needed;
-
-	int			magic;
-	int			baud_base;
-	int			port;
-	int			irq;
-	int			flags; 		/* defined in tty.h */
-	int			type; 		/* UART type */
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			timeout;
-	int			xmit_fifo_size;
-	int			custom_divisor;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	unsigned long		event;
-	unsigned long		last_active;
-	int			line;
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-	struct work_struct	tqueue;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-
-	volatile struct dbdma_regs *tx_dma;
-	int			tx_dma_irq;
-	volatile struct dbdma_cmd *tx_cmds;
-	volatile struct mac_dma *rx;
-	int 			rx_dma_irq;
-	volatile struct dbdma_cmd **rx_cmds;
-	unsigned char		**rx_char_buf;
-	unsigned char		**rx_flag_buf;
-#define	RX_BUF_SIZE	256
-	int			rx_nbuf;
-	int			rx_done_bytes;
-	int			rx_ubuf;
-	int			rx_fbuf;
-#define	RX_NO_FBUF	(-1)
-	int			rx_cbuf;
-	spinlock_t		rx_dma_lock;
-	int			has_dma;
-	int			dma_initted;
-	void			*dma_priv;
-	struct timer_list	poll_dma_timer;
-#define RX_DMA_TIMER	(jiffies + 10*HZ/1000)
-
-	struct timer_list	powerup_timer;
-};
-
-
-#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	/* W/Req reflects recv if 1, xmit if 0 */
-#define	WT_FN_RDYFN	0x40	/* W/Req pin is DMA request if 1, wait if 0 */
-#define	WT_RDY_ENAB	0x80	/* Enable W/Req pin */
-
-/* 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 7' (Some enhanced feature control) */
-#define	ENEXREAD	0x40	/* Enable read of some write registers */
-
-/* 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	EN85C30	1	/* Enable some 85c30-enhanced registers */
-#define	ZCIE	2	/* Zero count IE */
-#define	ENSTFIFO 4	/* Enable status FIFO (SDLC) */
-#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 */
-#define	CHB_Tx_EMPTY	0x00
-#define	CHB_EXT_STAT	0x02
-#define	CHB_Rx_AVAIL	0x04
-#define	CHB_SPECIAL	0x06
-#define	CHA_Tx_EMPTY	0x08
-#define	CHA_EXT_STAT	0x0a
-#define	CHA_Rx_AVAIL	0x0c
-#define	CHA_SPECIAL	0x0e
-#define	STATUS_MASK	0x06
-
-/* 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 /* !(_MACSERIAL_H) */
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index b941ee2..4a0a0ad 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -63,6 +63,10 @@
 #include <asm/backlight.h>
 #endif
 
+#ifdef CONFIG_PPC32
+#include <asm/open_pic.h>
+#endif
+
 /* Some compile options */
 #undef SUSPEND_USES_PMU
 #define DEBUG_SLEEP
@@ -151,10 +155,10 @@
 static u8 pmu_intr_mask;
 static int pmu_version;
 static int drop_interrupts;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 static int option_lid_wakeup = 1;
 static int sleep_in_progress;
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 static unsigned long async_req_locks;
 static unsigned int pmu_irq_stats[11];
 
@@ -164,7 +168,6 @@
 static struct proc_dir_entry *proc_pmu_options;
 static int option_server_mode;
 
-#ifdef CONFIG_PMAC_PBOOK
 int pmu_battery_count;
 int pmu_cur_battery;
 unsigned int pmu_power_flags;
@@ -172,7 +175,6 @@
 static int query_batt_timer = BATTERY_POLLING_COUNT;
 static struct adb_request batt_req;
 static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
-#endif /* CONFIG_PMAC_PBOOK */
 
 #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
 extern int disable_kernel_backlight;
@@ -206,11 +208,9 @@
 static int pmu_set_backlight_level(int level, void* data);
 static int pmu_set_backlight_enable(int on, int level, void* data);
 #endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
 static void pmu_pass_intr(unsigned char *data, int len);
 static int proc_get_batt(char *page, char **start, off_t off,
 			int count, int *eof, void *data);
-#endif /* CONFIG_PMAC_PBOOK */
 static int proc_read_options(char *page, char **start, off_t off,
 			int count, int *eof, void *data);
 static int proc_write_options(struct file *file, const char __user *buffer,
@@ -403,8 +403,12 @@
 
 	bright_req_1.complete = 1;
 	bright_req_2.complete = 1;
-#ifdef CONFIG_PMAC_PBOOK
 	batt_req.complete = 1;
+
+#ifdef CONFIG_PPC32
+	if (pmu_kind == PMU_KEYLARGO_BASED)
+		openpic_set_irq_priority(vias->intrs[0].line,
+					 OPENPIC_PRIORITY_DEFAULT + 1);
 #endif
 
 	if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
@@ -458,7 +462,7 @@
 	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC32
   	if (machine_is_compatible("AAPL,3400/2400") ||
   		machine_is_compatible("AAPL,3500")) {
 		int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
@@ -486,20 +490,19 @@
 				pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
 		}
 	}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC32 */
+
 	/* Create /proc/pmu */
 	proc_pmu_root = proc_mkdir("pmu", NULL);
 	if (proc_pmu_root) {
-#ifdef CONFIG_PMAC_PBOOK
-		int i;
+		long i;
 
 		for (i=0; i<pmu_battery_count; i++) {
 			char title[16];
-			sprintf(title, "battery_%d", i);
+			sprintf(title, "battery_%ld", i);
 			proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root,
 						proc_get_batt, (void *)i);
 		}
-#endif /* CONFIG_PMAC_PBOOK */
 
 		proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
 					proc_get_info, NULL);
@@ -619,8 +622,6 @@
 	pmu_wait_complete(&req);
 }
 
-#ifdef CONFIG_PMAC_PBOOK
-
 /* This new version of the code for 2400/3400/3500 powerbooks
  * is inspired from the implementation in gkrellm-pmu
  */
@@ -803,8 +804,6 @@
 			2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
 }
 
-#endif /* CONFIG_PMAC_PBOOK */
-
 static int __pmac
 proc_get_info(char *page, char **start, off_t off,
 		int count, int *eof, void *data)
@@ -813,11 +812,9 @@
 
 	p += sprintf(p, "PMU driver version     : %d\n", PMU_DRIVER_VERSION);
 	p += sprintf(p, "PMU firmware version   : %02x\n", pmu_version);
-#ifdef CONFIG_PMAC_PBOOK
 	p += sprintf(p, "AC Power               : %d\n",
 		((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0));
 	p += sprintf(p, "Battery count          : %d\n", pmu_battery_count);
-#endif /* CONFIG_PMAC_PBOOK */
 
 	return p - page;
 }
@@ -849,12 +846,11 @@
 	return p - page;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
 static int __pmac
 proc_get_batt(char *page, char **start, off_t off,
 		int count, int *eof, void *data)
 {
-	int batnum = (int)data;
+	long batnum = (long)data;
 	char *p = page;
 	
 	p += sprintf(p, "\n");
@@ -873,7 +869,6 @@
 
 	return p - page;
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
 static int __pmac
 proc_read_options(char *page, char **start, off_t off,
@@ -881,11 +876,11 @@
 {
 	char *p = page;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	if (pmu_kind == PMU_KEYLARGO_BASED &&
 	    pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
 		p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif
 	if (pmu_kind == PMU_KEYLARGO_BASED)
 		p += sprintf(p, "server_mode=%d\n", option_server_mode);
 
@@ -922,12 +917,12 @@
 	*(val++) = 0;
 	while(*val == ' ')
 		val++;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	if (pmu_kind == PMU_KEYLARGO_BASED &&
 	    pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
 		if (!strcmp(label, "lid_wakeup"))
 			option_lid_wakeup = ((*val) == '1');
-#endif /* CONFIG_PMAC_PBOOK */
+#endif
 	if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
 		int new_value;
 		new_value = ((*val) == '1');
@@ -1422,7 +1417,6 @@
 	}
 	/* Tick interrupt */
 	else if ((1 << pirq) & PMU_INT_TICK) {
-#ifdef CONFIG_PMAC_PBOOK
 		/* Environement or tick interrupt, query batteries */
 		if (pmu_battery_count) {
 			if ((--query_batt_timer) == 0) {
@@ -1437,7 +1431,6 @@
 		pmu_pass_intr(data, len);
 	} else {
 	       pmu_pass_intr(data, len);
-#endif /* CONFIG_PMAC_PBOOK */
 	}
 	goto next;
 }
@@ -2052,7 +2045,7 @@
 	return -1;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 
 static LIST_HEAD(sleep_notifiers);
 
@@ -2705,6 +2698,8 @@
 	return 0;
 }
 
+#endif /* CONFIG_PM */
+
 /*
  * Support for /dev/pmu device
  */
@@ -2884,11 +2879,11 @@
 pmu_ioctl(struct inode * inode, struct file *filp,
 		     u_int cmd, u_long arg)
 {
-	struct pmu_private *pp = filp->private_data;
 	__u32 __user *argp = (__u32 __user *)arg;
-	int error;
+	int error = -EINVAL;
 
 	switch (cmd) {
+#ifdef CONFIG_PM
 	case PMU_IOC_SLEEP:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
@@ -2910,12 +2905,13 @@
 			error = -ENOSYS;
 		}
 		sleep_in_progress = 0;
-		return error;
+		break;
 	case PMU_IOC_CAN_SLEEP:
 		if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
 			return put_user(0, argp);
 		else
 			return put_user(1, argp);
+#endif /* CONFIG_PM */
 
 #ifdef CONFIG_PMAC_BACKLIGHT
 	/* Backlight should have its own device or go via
@@ -2936,11 +2932,13 @@
 		error = get_user(value, argp);
 		if (!error)
 			error = set_backlight_level(value);
-		return error;
+		break;
 	}
 #ifdef CONFIG_INPUT_ADBHID
 	case PMU_IOC_GRAB_BACKLIGHT: {
+		struct pmu_private *pp = filp->private_data;
 		unsigned long flags;
+
 		if (pp->backlight_locker)
 			return 0;
 		pp->backlight_locker = 1;
@@ -2956,7 +2954,7 @@
 	case PMU_IOC_HAS_ADB:
 		return put_user(pmu_has_adb, argp);
 	}
-	return -EINVAL;
+	return error;
 }
 
 static struct file_operations pmu_device_fops __pmacdata = {
@@ -2972,14 +2970,16 @@
 	PMU_MINOR, "pmu", &pmu_device_fops
 };
 
-void pmu_device_init(void)
+static int pmu_device_init(void)
 {
 	if (!via)
-		return;
+		return 0;
 	if (misc_register(&pmu_device) < 0)
 		printk(KERN_ERR "via-pmu: cannot register misc device.\n");
+	return 0;
 }
-#endif /* CONFIG_PMAC_PBOOK */
+device_initcall(pmu_device_init);
+
 
 #ifdef DEBUG_SLEEP
 static inline void  __pmac
@@ -3147,12 +3147,12 @@
 EXPORT_SYMBOL(pmu_i2c_stdsub_write);
 EXPORT_SYMBOL(pmu_i2c_simple_read);
 EXPORT_SYMBOL(pmu_i2c_simple_write);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 EXPORT_SYMBOL(pmu_register_sleep_notifier);
 EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
 EXPORT_SYMBOL(pmu_enable_irled);
 EXPORT_SYMBOL(pmu_battery_count);
 EXPORT_SYMBOL(pmu_batteries);
 EXPORT_SYMBOL(pmu_power_flags);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index f9383e7..1b70f8b 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -7,7 +7,7 @@
 
 comment "Video Adapters"
 
-config CONFIG_TUNER_MULTI_I2C
+config TUNER_MULTI_I2C
 	bool "Enable support for multiple I2C devices on Video Adapters (EXPERIMENTAL)"
 	depends on VIDEO_DEV && EXPERIMENTAL
 	---help---
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 1247a25..9e1fe2e 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1274,6 +1274,7 @@
 module_param_array(io, int, NULL, 0);
 MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
 MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
+MODULE_LICENSE("GPL");
 
 int init_module(void)
 {
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 47e158f..2b55687 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1320,7 +1320,7 @@
 
 config CS89x0
 	tristate "CS89x0 support"
-	depends on NET_PCI && (ISA || ARCH_IXDP2X01)
+	depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105
 	---help---
 	  Support for CS89x0 chipset based Ethernet cards. If you have a
 	  network (Ethernet) card of this type, say Y and read the
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 3fe8ba9..f1bd45e 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1285,6 +1285,9 @@
 	b44_init_hw(bp);
 	bp->flags |= B44_FLAG_INIT_COMPLETE;
 
+	netif_carrier_off(dev);
+	b44_check_phy(bp);
+
 	spin_unlock_irq(&bp->lock);
 
 	init_timer(&bp->timer);
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 25e4495..b96d6fb 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -174,6 +174,13 @@
 #include <asm/irq.h>
 static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
+#elif defined(CONFIG_ARCH_PNX0105)
+#include <asm/irq.h>
+#include <asm/arch/gpio.h>
+#define CIRRUS_DEFAULT_BASE	IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000)	/* = Physical address 0x48200000 */
+#define CIRRUS_DEFAULT_IRQ	VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
+static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
+static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
 #else
 static unsigned int netcard_portlist[] __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
@@ -431,6 +438,30 @@
 #endif
         }
 
+#ifdef CONFIG_ARCH_PNX0105
+	initialize_ebi();
+
+	/* Map GPIO registers for the pins connected to the CS8900a. */
+	if (map_cirrus_gpio() < 0)
+		return -ENODEV;
+
+	reset_cirrus();
+
+	/* Map event-router registers. */
+	if (map_event_router() < 0)
+		return -ENODEV;
+
+	enable_cirrus_irq();
+
+	unmap_cirrus_gpio();
+	unmap_event_router();
+
+	dev->base_addr = ioaddr;
+
+	for (i = 0 ; i < 3 ; i++)
+		readreg(dev, 0);
+#endif
+
 	/* Grab the region so we can find another board if autoIRQ fails. */
 	/* WTF is going on here? */
 	if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
@@ -672,7 +703,7 @@
 	} else {
 		i = lp->isa_config & INT_NO_MASK;
 		if (lp->chip_type == CS8900) {
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
 		        i = cs8900_irq_map[0];
 #else
 			/* Translate the IRQ using the IRQ mapping table. */
@@ -1145,7 +1176,7 @@
 	int i;
 	int ret;
 
-#ifndef CONFIG_SH_HICOSH4 /* uses irq#1, so this won't work */
+#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */
 	if (dev->irq < 2) {
 		/* Allow interrupts to be generated by the chip */
 /* Cirrus' release had this: */
@@ -1176,7 +1207,7 @@
 	else
 #endif
 	{
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105)
 		if (((1 << dev->irq) & lp->irq_map) == 0) {
 			printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
@@ -1261,6 +1292,9 @@
 	case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
         default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
         }
+#ifdef CONFIG_ARCH_PNX0105
+	result = A_CNF_10B_T;
+#endif
         if (!result) {
                 printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
         release_irq:
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
index b0ef7ad..bd3ad8e 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/cs89x0.h
@@ -16,7 +16,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
 /* IXDP2401/IXDP2801 uses dword-aligned register addressing */
 #define CS89x0_PORT(reg) ((reg) * 2)
 #else
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index cfaa6b2b..1e56c8e 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1093,11 +1093,16 @@
 	}
 
 	if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && 
-		(mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && 
-		(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)))
-		/* enable/disable MDI/MDI-X auto-switching */
-		mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
-			nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
+	   (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) {
+		/* enable/disable MDI/MDI-X auto-switching.
+		   MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */
+		if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) ||
+		   (nic->mac == mac_82551_10) || (nic->mii.force_media) || 
+		   !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)) 
+			mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0);
+		else
+			mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH);
+	}
 
 	return 0;
 }
@@ -1666,8 +1671,10 @@
 	if(stat_ack & stat_ack_rnr)
 		nic->ru_running = RU_SUSPENDED;
 
-	e100_disable_irq(nic);
-	netif_rx_schedule(netdev);
+	if(likely(netif_rx_schedule_prep(netdev))) {
+		e100_disable_irq(nic);
+		__netif_rx_schedule(netdev);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -2335,11 +2342,11 @@
 		goto err_out_iounmap;
 	}
 
-	e100_phy_init(nic);
-
 	if((err = e100_eeprom_load(nic)))
 		goto err_out_free;
 
+	e100_phy_init(nic);
+
 	memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
 	if(!is_valid_ether_addr(netdev->dev_addr)) {
 		DPRINTK(PROBE, ERR, "Invalid MAC address from "
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index af1e82c..092757b 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -140,7 +140,7 @@
 #define E1000_RX_BUFFER_WRITE	16	/* Must be power of 2 */
 
 #define AUTO_ALL_MODES            0
-#define E1000_EEPROM_82544_APM    0x0400
+#define E1000_EEPROM_82544_APM    0x0004
 #define E1000_EEPROM_APME         0x0400
 
 #ifndef E1000_MASTER_SLAVE
@@ -159,7 +159,7 @@
  * so a DMA handle can be stored along with the buffer */
 struct e1000_buffer {
 	struct sk_buff *skb;
-	uint64_t dma;
+	dma_addr_t dma;
 	unsigned long time_stamp;
 	uint16_t length;
 	uint16_t next_to_watch;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 237247f..f133ff0 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -105,7 +105,7 @@
 static int
 e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	if(hw->media_type == e1000_media_type_copper) {
@@ -141,9 +141,9 @@
 				     SUPPORTED_FIBRE |
 				     SUPPORTED_Autoneg);
 
-		ecmd->advertising = (SUPPORTED_1000baseT_Full |
-				     SUPPORTED_FIBRE |
-				     SUPPORTED_Autoneg);
+		ecmd->advertising = (ADVERTISED_1000baseT_Full |
+				     ADVERTISED_FIBRE |
+				     ADVERTISED_Autoneg);
 
 		ecmd->port = PORT_FIBRE;
 
@@ -179,13 +179,24 @@
 static int
 e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	if(ecmd->autoneg == AUTONEG_ENABLE) {
 		hw->autoneg = 1;
-		hw->autoneg_advertised = 0x002F;
-		ecmd->advertising = 0x002F;
+		if(hw->media_type == e1000_media_type_fiber)
+			hw->autoneg_advertised = ADVERTISED_1000baseT_Full |
+				     ADVERTISED_FIBRE |
+				     ADVERTISED_Autoneg;
+		else 
+			hw->autoneg_advertised = ADVERTISED_10baseT_Half |
+						  ADVERTISED_10baseT_Full |
+						  ADVERTISED_100baseT_Half |
+						  ADVERTISED_100baseT_Full |
+						  ADVERTISED_1000baseT_Full|
+						  ADVERTISED_Autoneg |
+						  ADVERTISED_TP;
+		ecmd->advertising = hw->autoneg_advertised;
 	} else
 		if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
 			return -EINVAL;
@@ -206,7 +217,7 @@
 e1000_get_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *pause)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	pause->autoneg = 
@@ -226,7 +237,7 @@
 e1000_set_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *pause)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	
 	adapter->fc_autoneg = pause->autoneg;
@@ -259,14 +270,14 @@
 static uint32_t
 e1000_get_rx_csum(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	return adapter->rx_csum;
 }
 
 static int
 e1000_set_rx_csum(struct net_device *netdev, uint32_t data)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	adapter->rx_csum = data;
 
 	if(netif_running(netdev)) {
@@ -286,7 +297,7 @@
 static int
 e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	if(adapter->hw.mac_type < e1000_82543) {
 		if (!data)
@@ -306,8 +317,8 @@
 static int
 e1000_set_tso(struct net_device *netdev, uint32_t data)
 {
-	struct e1000_adapter *adapter = netdev->priv;
-	if ((adapter->hw.mac_type < e1000_82544) ||
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	if((adapter->hw.mac_type < e1000_82544) ||
 	    (adapter->hw.mac_type == e1000_82547)) 
 		return data ? -EINVAL : 0;
 
@@ -322,14 +333,14 @@
 static uint32_t
 e1000_get_msglevel(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	return adapter->msg_enable;
 }
 
 static void
 e1000_set_msglevel(struct net_device *netdev, uint32_t data)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	adapter->msg_enable = data;
 }
 
@@ -344,7 +355,7 @@
 e1000_get_regs(struct net_device *netdev,
 	       struct ethtool_regs *regs, void *p)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	uint32_t *regs_buff = p;
 	uint16_t phy_data;
@@ -432,7 +443,7 @@
 static int
 e1000_get_eeprom_len(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	return adapter->hw.eeprom.word_size * 2;
 }
 
@@ -440,7 +451,7 @@
 e1000_get_eeprom(struct net_device *netdev,
                       struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	uint16_t *eeprom_buff;
 	int first_word, last_word;
@@ -486,7 +497,7 @@
 e1000_set_eeprom(struct net_device *netdev,
                       struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	uint16_t *eeprom_buff;
 	void *ptr;
@@ -547,7 +558,7 @@
 e1000_get_drvinfo(struct net_device *netdev,
                        struct ethtool_drvinfo *drvinfo)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	strncpy(drvinfo->driver,  e1000_driver_name, 32);
 	strncpy(drvinfo->version, e1000_driver_version, 32);
@@ -563,7 +574,7 @@
 e1000_get_ringparam(struct net_device *netdev,
                     struct ethtool_ringparam *ring)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	e1000_mac_type mac_type = adapter->hw.mac_type;
 	struct e1000_desc_ring *txdr = &adapter->tx_ring;
 	struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -584,7 +595,7 @@
 e1000_set_ringparam(struct net_device *netdev,
                     struct ethtool_ringparam *ring)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	e1000_mac_type mac_type = adapter->hw.mac_type;
 	struct e1000_desc_ring *txdr = &adapter->tx_ring;
 	struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -651,6 +662,9 @@
 		E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W));             \
 		value = E1000_READ_REG(&adapter->hw, R);                       \
 		if(value != (test[pat] & W & M)) {                             \
+			DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \
+			        "0x%08X expected 0x%08X\n",                    \
+			        E1000_##R, value, (test[pat] & W & M));        \
 			*data = (adapter->hw.mac_type < e1000_82543) ?         \
 				E1000_82542_##R : E1000_##R;                   \
 			return 1;                                              \
@@ -663,7 +677,9 @@
 	uint32_t value;                                                        \
 	E1000_WRITE_REG(&adapter->hw, R, W & M);                               \
 	value = E1000_READ_REG(&adapter->hw, R);                               \
-	if ((W & M) != (value & M)) {                                          \
+	if((W & M) != (value & M)) {                                          \
+		DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
+		        "expected 0x%08X\n", E1000_##R, (value & M), (W & M)); \
 		*data = (adapter->hw.mac_type < e1000_82543) ?                 \
 			E1000_82542_##R : E1000_##R;                           \
 		return 1;                                                      \
@@ -673,18 +689,33 @@
 static int
 e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
 {
-	uint32_t value;
-	uint32_t i;
+	uint32_t value, before, after;
+	uint32_t i, toggle;
 
 	/* The status register is Read Only, so a write should fail.
 	 * Some bits that get toggled are ignored.
 	 */
-	value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833));
-	E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF));
-	if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) {
+        switch (adapter->hw.mac_type) {
+	case e1000_82573:
+		toggle = 0x7FFFF033;
+		break;
+	default:
+		toggle = 0xFFFFF833;
+		break;
+	}
+
+	before = E1000_READ_REG(&adapter->hw, STATUS);
+	value = (E1000_READ_REG(&adapter->hw, STATUS) & toggle);
+	E1000_WRITE_REG(&adapter->hw, STATUS, toggle);
+	after = E1000_READ_REG(&adapter->hw, STATUS) & toggle;
+	if(value != after) {
+		DPRINTK(DRV, ERR, "failed STATUS register test got: "
+		        "0x%08X expected: 0x%08X\n", after, value);
 		*data = 1;
 		return 1;
 	}
+	/* restore previous status */
+	E1000_WRITE_REG(&adapter->hw, STATUS, before);
 
 	REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
 	REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
@@ -766,7 +797,7 @@
 		struct pt_regs *regs)
 {
 	struct net_device *netdev = (struct net_device *) data;
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR);
 
@@ -1214,6 +1245,7 @@
 	case e1000_82541_rev_2:
 	case e1000_82547:
 	case e1000_82547_rev_2:
+	case e1000_82573:
 		return e1000_integrated_phy_loopback(adapter);
 		break;
 
@@ -1422,7 +1454,7 @@
 e1000_diag_test(struct net_device *netdev,
 		   struct ethtool_test *eth_test, uint64_t *data)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	boolean_t if_running = netif_running(netdev);
 
 	if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
@@ -1482,7 +1514,7 @@
 static void
 e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	switch(adapter->hw.device_id) {
@@ -1527,7 +1559,7 @@
 static int
 e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	switch(adapter->hw.device_id) {
@@ -1588,22 +1620,31 @@
 static int
 e1000_phys_id(struct net_device *netdev, uint32_t data)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
 		data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
 
-	if(!adapter->blink_timer.function) {
-		init_timer(&adapter->blink_timer);
-		adapter->blink_timer.function = e1000_led_blink_callback;
-		adapter->blink_timer.data = (unsigned long) adapter;
+	if(adapter->hw.mac_type < e1000_82573) {
+		if(!adapter->blink_timer.function) {
+			init_timer(&adapter->blink_timer);
+			adapter->blink_timer.function = e1000_led_blink_callback;
+			adapter->blink_timer.data = (unsigned long) adapter;
+		}
+		e1000_setup_led(&adapter->hw);
+		mod_timer(&adapter->blink_timer, jiffies);
+		msleep_interruptible(data * 1000);
+		del_timer_sync(&adapter->blink_timer);
+	}
+	else {
+		E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
+			E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | 
+			(E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
+			(E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) |
+			(E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT)));
+		msleep_interruptible(data * 1000);
 	}
 
-	e1000_setup_led(&adapter->hw);
-	mod_timer(&adapter->blink_timer, jiffies);
-
-	msleep_interruptible(data * 1000);
-	del_timer_sync(&adapter->blink_timer);
 	e1000_led_off(&adapter->hw);
 	clear_bit(E1000_LED_ON, &adapter->led_status);
 	e1000_cleanup_led(&adapter->hw);
@@ -1614,7 +1655,7 @@
 static int
 e1000_nway_reset(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	if(netif_running(netdev)) {
 		e1000_down(adapter);
 		e1000_up(adapter);
@@ -1632,7 +1673,7 @@
 e1000_get_ethtool_stats(struct net_device *netdev, 
 		struct ethtool_stats *stats, uint64_t *data)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int i;
 
 	e1000_update_stats(adapter);
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 723589b..045f542 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -354,18 +354,27 @@
         hw->media_type = e1000_media_type_internal_serdes;
         break;
     default:
-        if(hw->mac_type >= e1000_82543) {
+        switch (hw->mac_type) {
+        case e1000_82542_rev2_0:
+        case e1000_82542_rev2_1:
+            hw->media_type = e1000_media_type_fiber;
+            break;
+        case e1000_82573:
+            /* The STATUS_TBIMODE bit is reserved or reused for the this
+             * device.
+             */
+            hw->media_type = e1000_media_type_copper;
+            break;
+        default:
             status = E1000_READ_REG(hw, STATUS);
-            if(status & E1000_STATUS_TBIMODE) {
+            if (status & E1000_STATUS_TBIMODE) {
                 hw->media_type = e1000_media_type_fiber;
                 /* tbi_compatibility not valid on fiber */
                 hw->tbi_compatibility_en = FALSE;
             } else {
                 hw->media_type = e1000_media_type_copper;
             }
-        } else {
-            /* This is an 82542 (fiber only) */
-            hw->media_type = e1000_media_type_fiber;
+            break;
         }
     }
 }
@@ -1189,9 +1198,9 @@
         ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
         if(ret_val)
             return ret_val;
-        }
+    }
 
-   return E1000_SUCCESS;
+    return E1000_SUCCESS;
 }
 
 
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index a0263ee..93e9f87 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -66,6 +66,7 @@
     e1000_eeprom_spi,
     e1000_eeprom_microwire,
     e1000_eeprom_flash,
+    e1000_eeprom_none, /* No NVM support */
     e1000_num_eeprom_types
 } e1000_eeprom_type;
 
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 137226d..cb7f051 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -29,6 +29,8 @@
 #include "e1000.h"
 
 /* Change Log
+ * 6.0.58       4/20/05
+ *   o Accepted ethtool cleanup patch from Stephen Hemminger 
  * 6.0.44+	2/15/05
  *   o applied Anton's patch to resolve tx hang in hardware
  *   o Applied Andrew Mortons patch - e1000 stops working after resume
@@ -41,9 +43,9 @@
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-#define DRV_VERSION "6.0.54-k2"DRIVERNAPI
+#define DRV_VERSION		"6.0.60-k2"DRIVERNAPI
 char e1000_driver_version[] = DRV_VERSION;
-char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
+char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
  *
@@ -517,7 +519,7 @@
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	pci_set_drvdata(pdev, netdev);
-	adapter = netdev->priv;
+	adapter = netdev_priv(netdev);
 	adapter->netdev = netdev;
 	adapter->pdev = pdev;
 	adapter->hw.back = adapter;
@@ -738,7 +740,7 @@
 e1000_remove(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	uint32_t manc, swsm;
 
 	flush_scheduled_work();
@@ -871,7 +873,7 @@
 static int
 e1000_open(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int err;
 
 	/* allocate transmit descriptors */
@@ -919,7 +921,7 @@
 static int
 e1000_close(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	e1000_down(adapter);
 
@@ -1599,7 +1601,7 @@
 static int
 e1000_set_mac(struct net_device *netdev, void *p)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct sockaddr *addr = p;
 
 	if(!is_valid_ether_addr(addr->sa_data))
@@ -1634,7 +1636,7 @@
 static void
 e1000_set_multi(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	struct dev_mc_list *mc_ptr;
 	unsigned long flags;
@@ -2213,7 +2215,7 @@
 static int
 e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
 	unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
 	unsigned int tx_flags = 0;
@@ -2344,7 +2346,7 @@
 static void
 e1000_tx_timeout(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	/* Do the reset outside of interrupt context */
 	schedule_work(&adapter->tx_timeout_task);
@@ -2353,7 +2355,7 @@
 static void
 e1000_tx_timeout_task(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	e1000_down(adapter);
 	e1000_up(adapter);
@@ -2370,7 +2372,7 @@
 static struct net_device_stats *
 e1000_get_stats(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	e1000_update_stats(adapter);
 	return &adapter->net_stats;
@@ -2387,7 +2389,7 @@
 static int
 e1000_change_mtu(struct net_device *netdev, int new_mtu)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 
 	if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
@@ -2598,7 +2600,7 @@
 e1000_intr(int irq, void *data, struct pt_regs *regs)
 {
 	struct net_device *netdev = data;
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	uint32_t icr = E1000_READ_REG(hw, ICR);
 #ifndef CONFIG_E1000_NAPI
@@ -2661,7 +2663,7 @@
 static int
 e1000_clean(struct net_device *netdev, int *budget)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int work_to_do = min(*budget, netdev->quota);
 	int tx_cleaned;
 	int work_done = 0;
@@ -2672,8 +2674,8 @@
 	*budget -= work_done;
 	netdev->quota -= work_done;
 	
-	/* If no Tx and no Rx work done, exit the polling mode */
 	if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+	/* If no Tx and not enough Rx work done, exit the polling mode */
 		netif_rx_complete(netdev);
 		e1000_irq_enable(adapter);
 		return 0;
@@ -2769,13 +2771,13 @@
 			i = tx_ring->next_to_clean;
 			eop = tx_ring->buffer_info[i].next_to_watch;
 			eop_desc = E1000_TX_DESC(*tx_ring, eop);
-			DPRINTK(TX_ERR, ERR, "Detected Tx Unit Hang\n"
+			DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
 					"  TDH                  <%x>\n"
 					"  TDT                  <%x>\n"
 					"  next_to_use          <%x>\n"
 					"  next_to_clean        <%x>\n"
 					"buffer_info[next_to_clean]\n"
-					"  dma                  <%llx>\n"
+					"  dma                  <%zx>\n"
 					"  time_stamp           <%lx>\n"
 					"  next_to_watch        <%x>\n"
 					"  jiffies              <%lx>\n"
@@ -2994,7 +2996,7 @@
 
 	i = rx_ring->next_to_clean;
 	rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
-	staterr = rx_desc->wb.middle.status_error;
+	staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
 
 	while(staterr & E1000_RXD_STAT_DD) {
 		buffer_info = &rx_ring->buffer_info[i];
@@ -3065,16 +3067,16 @@
 #ifdef CONFIG_E1000_NAPI
 		if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
 			vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
-				le16_to_cpu(rx_desc->wb.middle.vlan &
-					E1000_RXD_SPC_VLAN_MASK));
+				le16_to_cpu(rx_desc->wb.middle.vlan) &
+				E1000_RXD_SPC_VLAN_MASK);
 		} else {
 			netif_receive_skb(skb);
 		}
 #else /* CONFIG_E1000_NAPI */
 		if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
 			vlan_hwaccel_rx(skb, adapter->vlgrp,
-				le16_to_cpu(rx_desc->wb.middle.vlan &
-					E1000_RXD_SPC_VLAN_MASK));
+				le16_to_cpu(rx_desc->wb.middle.vlan) &
+				E1000_RXD_SPC_VLAN_MASK);
 		} else {
 			netif_rx(skb);
 		}
@@ -3087,7 +3089,7 @@
 		if(unlikely(++i == rx_ring->count)) i = 0;
 
 		rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
-		staterr = rx_desc->wb.middle.status_error;
+		staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
 	}
 	rx_ring->next_to_clean = i;
 	adapter->alloc_rx_buf(adapter);
@@ -3371,11 +3373,12 @@
 static int
 e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct mii_ioctl_data *data = if_mii(ifr);
 	int retval;
 	uint16_t mii_reg;
 	uint16_t spddplx;
+	unsigned long flags;
 
 	if(adapter->hw.media_type != e1000_media_type_copper)
 		return -EOPNOTSUPP;
@@ -3385,22 +3388,29 @@
 		data->phy_id = adapter->hw.phy_addr;
 		break;
 	case SIOCGMIIREG:
-		if (!capable(CAP_NET_ADMIN))
+		if(!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
-				   &data->val_out))
+		spin_lock_irqsave(&adapter->stats_lock, flags);
+		if(e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+				   &data->val_out)) {
+			spin_unlock_irqrestore(&adapter->stats_lock, flags);
 			return -EIO;
+		}
+		spin_unlock_irqrestore(&adapter->stats_lock, flags);
 		break;
 	case SIOCSMIIREG:
-		if (!capable(CAP_NET_ADMIN))
+		if(!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		if (data->reg_num & ~(0x1F))
+		if(data->reg_num & ~(0x1F))
 			return -EFAULT;
 		mii_reg = data->val_in;
-		if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
-					mii_reg))
+		spin_lock_irqsave(&adapter->stats_lock, flags);
+		if(e1000_write_phy_reg(&adapter->hw, data->reg_num,
+					mii_reg)) {
+			spin_unlock_irqrestore(&adapter->stats_lock, flags);
 			return -EIO;
-		if (adapter->hw.phy_type == e1000_phy_m88) {
+		}
+		if(adapter->hw.phy_type == e1000_phy_m88) {
 			switch (data->reg_num) {
 			case PHY_CTRL:
 				if(mii_reg & MII_CR_POWER_DOWN)
@@ -3420,8 +3430,12 @@
 						   HALF_DUPLEX;
 					retval = e1000_set_spd_dplx(adapter,
 								    spddplx);
-					if(retval)
+					if(retval) {
+						spin_unlock_irqrestore(
+							&adapter->stats_lock, 
+							flags);
 						return retval;
+					}
 				}
 				if(netif_running(adapter->netdev)) {
 					e1000_down(adapter);
@@ -3431,8 +3445,11 @@
 				break;
 			case M88E1000_PHY_SPEC_CTRL:
 			case M88E1000_EXT_PHY_SPEC_CTRL:
-				if (e1000_phy_reset(&adapter->hw))
+				if(e1000_phy_reset(&adapter->hw)) {
+					spin_unlock_irqrestore(
+						&adapter->stats_lock, flags);
 					return -EIO;
+				}
 				break;
 			}
 		} else {
@@ -3448,6 +3465,7 @@
 				break;
 			}
 		}
+		spin_unlock_irqrestore(&adapter->stats_lock, flags);
 		break;
 	default:
 		return -EOPNOTSUPP;
@@ -3504,7 +3522,7 @@
 static void
 e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	uint32_t ctrl, rctl;
 
 	e1000_irq_disable(adapter);
@@ -3544,7 +3562,7 @@
 static void
 e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	uint32_t vfta, index;
 	if((adapter->hw.mng_cookie.status &
 		E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
@@ -3560,7 +3578,7 @@
 static void
 e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	uint32_t vfta, index;
 
 	e1000_irq_disable(adapter);
@@ -3601,6 +3619,13 @@
 {
 	adapter->hw.autoneg = 0;
 
+	/* Fiber NICs only allow 1000 gbps Full duplex */
+	if((adapter->hw.media_type == e1000_media_type_fiber) &&
+		spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+		DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n");
+		return -EINVAL;
+	}
+
 	switch(spddplx) {
 	case SPEED_10 + DUPLEX_HALF:
 		adapter->hw.forced_speed_duplex = e1000_10_half;
@@ -3647,7 +3672,7 @@
 e1000_suspend(struct pci_dev *pdev, uint32_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm;
 	uint32_t wufc = adapter->wol;
 
@@ -3740,12 +3765,12 @@
 e1000_resume(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct e1000_adapter *adapter = netdev->priv;
-	uint32_t manc, ret, swsm;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	uint32_t manc, ret_val, swsm;
 
 	pci_set_power_state(pdev, 0);
 	pci_restore_state(pdev);
-	ret = pci_enable_device(pdev);
+	ret_val = pci_enable_device(pdev);
 	pci_set_master(pdev);
 
 	pci_enable_wake(pdev, 3, 0);
@@ -3788,7 +3813,7 @@
 static void
 e1000_netpoll(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	disable_irq(adapter->pdev->irq);
 	e1000_intr(adapter->pdev->irq, netdev, NULL);
 	enable_irq(adapter->pdev->irq);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 4ebcd05..64f0f69 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -82,6 +82,9 @@
  *	0.31: 14 Nov 2004: ethtool support for getting/setting link
  *	                   capabilities.
  *	0.32: 16 Apr 2005: RX_ERROR4 handling added.
+ *	0.33: 16 May 2005: Support for MCP51 added.
+ *	0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
+ *	0.35: 26 Jun 2005: Support for MCP55 added.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -93,7 +96,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION		"0.32"
+#define FORCEDETH_VERSION		"0.35"
 #define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
@@ -2005,7 +2008,9 @@
 	/* handle different descriptor versions */
 	if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
 		pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
-		pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3)
+		pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||    
+		pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+		pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
 		np->desc_ver = DESC_VER_1;
 	else
 		np->desc_ver = DESC_VER_2;
@@ -2215,56 +2220,84 @@
 		.device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_ANY_ID,
-		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
 	},
 	{	/* nForce3 Ethernet Controller */
 		.vendor = PCI_VENDOR_ID_NVIDIA,
 		.device = PCI_DEVICE_ID_NVIDIA_NVENET_5,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_ANY_ID,
-		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
 	},
 	{	/* nForce3 Ethernet Controller */
 		.vendor = PCI_VENDOR_ID_NVIDIA,
 		.device = PCI_DEVICE_ID_NVIDIA_NVENET_6,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_ANY_ID,
-		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
 	},
 	{	/* nForce3 Ethernet Controller */
 		.vendor = PCI_VENDOR_ID_NVIDIA,
 		.device = PCI_DEVICE_ID_NVIDIA_NVENET_7,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_ANY_ID,
-		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
 	},
 	{	/* CK804 Ethernet Controller */
 		.vendor = PCI_VENDOR_ID_NVIDIA,
 		.device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_ANY_ID,
-		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
 	},
 	{	/* CK804 Ethernet Controller */
 		.vendor = PCI_VENDOR_ID_NVIDIA,
 		.device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_ANY_ID,
-		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
 	},
 	{	/* MCP04 Ethernet Controller */
 		.vendor = PCI_VENDOR_ID_NVIDIA,
 		.device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_ANY_ID,
-		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
 	},
 	{	/* MCP04 Ethernet Controller */
 		.vendor = PCI_VENDOR_ID_NVIDIA,
 		.device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_ANY_ID,
-		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+	},
+	{	/* MCP51 Ethernet Controller */
+		.vendor = PCI_VENDOR_ID_NVIDIA,
+		.device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+	},
+	{	/* MCP51 Ethernet Controller */
+		.vendor = PCI_VENDOR_ID_NVIDIA,
+		.device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+	},
+	{	/* MCP55 Ethernet Controller */
+		.vendor = PCI_VENDOR_ID_NVIDIA,
+		.device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+	},
+	{	/* MCP55 Ethernet Controller */
+		.vendor = PCI_VENDOR_ID_NVIDIA,
+		.device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+		.driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
 	},
 	{0,},
 };
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index b43b2b1..6518334 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * drivers/net/gianfar.c
  *
  * Gianfar Ethernet Driver
@@ -22,10 +22,9 @@
  *  B-V +1.62
  *
  *  Theory of operation
- *  This driver is designed for the Triple-speed Ethernet
- *  controllers on the Freescale 8540/8560 integrated processors,
- *  as well as the Fast Ethernet Controller on the 8540.  
- *  
+ *  This driver is designed for the non-CPM ethernet controllers
+ *  on the 85xx and 83xx family of integrated processors
+ *
  *  The driver is initialized through platform_device.  Structures which
  *  define the configuration needed by the board are defined in a
  *  board structure in arch/ppc/platforms (though I do not
@@ -39,12 +38,12 @@
  *
  *  The Gianfar Ethernet Controller uses a ring of buffer
  *  descriptors.  The beginning is indicated by a register
- *  pointing to the physical address of the start of the ring. 
- *  The end is determined by a "wrap" bit being set in the 
+ *  pointing to the physical address of the start of the ring.
+ *  The end is determined by a "wrap" bit being set in the
  *  last descriptor of the ring.
  *
  *  When a packet is received, the RXF bit in the
- *  IEVENT register is set, triggering an interrupt when the 
+ *  IEVENT register is set, triggering an interrupt when the
  *  corresponding bit in the IMASK register is also set (if
  *  interrupt coalescing is active, then the interrupt may not
  *  happen immediately, but will wait until either a set number
@@ -52,7 +51,7 @@
  *  interrupt handler will signal there is work to be done, and
  *  exit.  Without NAPI, the packet(s) will be handled
  *  immediately.  Both methods will start at the last known empty
- *  descriptor, and process every subsequent descriptor until there 
+ *  descriptor, and process every subsequent descriptor until there
  *  are none left with data (NAPI will stop after a set number of
  *  packets to give time to other tasks, but will eventually
  *  process all the packets).  The data arrives inside a
@@ -83,9 +82,13 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/if_vlan.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/device.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -123,7 +126,7 @@
 static int gfar_change_mtu(struct net_device *dev, int new_mtu);
 static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void gfar_phy_change(void *data);
@@ -139,9 +142,12 @@
 #ifdef CONFIG_GFAR_NAPI
 static int gfar_poll(struct net_device *dev, int *budget);
 #endif
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
 static void gfar_phy_startup_timer(unsigned long data);
+static void gfar_vlan_rx_register(struct net_device *netdev,
+		                struct vlan_group *grp);
+static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 
 extern struct ethtool_ops gfar_ethtool_ops;
 
@@ -149,6 +155,13 @@
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
 MODULE_LICENSE("GPL");
 
+int gfar_uses_fcb(struct gfar_private *priv)
+{
+	if (priv->vlan_enable || priv->rx_csum_enable)
+		return 1;
+	else
+		return 0;
+}
 static int gfar_probe(struct device *device)
 {
 	u32 tempval;
@@ -159,7 +172,6 @@
 	struct resource *r;
 	int idx;
 	int err = 0;
-	int dev_ethtool_ops = 0;
 
 	einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
 
@@ -265,15 +277,69 @@
 	dev->mtu = 1500;
 	dev->set_multicast_list = gfar_set_multi;
 
-	/* Index into the array of possible ethtool
-	 * ops to catch all 4 possibilities */
-	if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) == 0)
-		dev_ethtool_ops += 1;
+	dev->ethtool_ops = &gfar_ethtool_ops;
 
-	if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE) == 0)
-		dev_ethtool_ops += 2;
+	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
+		priv->rx_csum_enable = 1;
+		dev->features |= NETIF_F_IP_CSUM;
+	} else
+		priv->rx_csum_enable = 0;
 
-	dev->ethtool_ops = gfar_op_array[dev_ethtool_ops];
+	priv->vlgrp = NULL;
+
+	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
+		dev->vlan_rx_register = gfar_vlan_rx_register;
+		dev->vlan_rx_kill_vid = gfar_vlan_rx_kill_vid;
+
+		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
+		priv->vlan_enable = 1;
+	}
+
+	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
+		priv->extended_hash = 1;
+		priv->hash_width = 9;
+
+		priv->hash_regs[0] = &priv->regs->igaddr0;
+		priv->hash_regs[1] = &priv->regs->igaddr1;
+		priv->hash_regs[2] = &priv->regs->igaddr2;
+		priv->hash_regs[3] = &priv->regs->igaddr3;
+		priv->hash_regs[4] = &priv->regs->igaddr4;
+		priv->hash_regs[5] = &priv->regs->igaddr5;
+		priv->hash_regs[6] = &priv->regs->igaddr6;
+		priv->hash_regs[7] = &priv->regs->igaddr7;
+		priv->hash_regs[8] = &priv->regs->gaddr0;
+		priv->hash_regs[9] = &priv->regs->gaddr1;
+		priv->hash_regs[10] = &priv->regs->gaddr2;
+		priv->hash_regs[11] = &priv->regs->gaddr3;
+		priv->hash_regs[12] = &priv->regs->gaddr4;
+		priv->hash_regs[13] = &priv->regs->gaddr5;
+		priv->hash_regs[14] = &priv->regs->gaddr6;
+		priv->hash_regs[15] = &priv->regs->gaddr7;
+
+	} else {
+		priv->extended_hash = 0;
+		priv->hash_width = 8;
+
+		priv->hash_regs[0] = &priv->regs->gaddr0;
+                priv->hash_regs[1] = &priv->regs->gaddr1;
+		priv->hash_regs[2] = &priv->regs->gaddr2;
+		priv->hash_regs[3] = &priv->regs->gaddr3;
+		priv->hash_regs[4] = &priv->regs->gaddr4;
+		priv->hash_regs[5] = &priv->regs->gaddr5;
+		priv->hash_regs[6] = &priv->regs->gaddr6;
+		priv->hash_regs[7] = &priv->regs->gaddr7;
+	}
+
+	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
+		priv->padding = DEFAULT_PADDING;
+	else
+		priv->padding = 0;
+
+	dev->hard_header_len += priv->padding;
+
+	if (dev->features & NETIF_F_IP_CSUM)
+		dev->hard_header_len += GMAC_FCB_LEN;
 
 	priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
 #ifdef CONFIG_GFAR_BUFSTASH
@@ -289,6 +355,9 @@
 	priv->rxcount = DEFAULT_RXCOUNT;
 	priv->rxtime = DEFAULT_RXTIME;
 
+	/* Enable most messages by default */
+	priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+
 	err = register_netdev(dev);
 
 	if (err) {
@@ -360,8 +429,9 @@
 			GFP_KERNEL);
 
 	if(NULL == mii_info) {
-		printk(KERN_ERR "%s: Could not allocate mii_info\n", 
-				dev->name);
+		if (netif_msg_ifup(priv))
+			printk(KERN_ERR "%s: Could not allocate mii_info\n",
+					dev->name);
 		return -ENOMEM;
 	}
 
@@ -410,7 +480,8 @@
 	curphy = get_phy_info(priv->mii_info);
 
 	if (curphy == NULL) {
-		printk(KERN_ERR "%s: No PHY found\n", dev->name);
+		if (netif_msg_ifup(priv))
+			printk(KERN_ERR "%s: No PHY found\n", dev->name);
 		err = -1;
 		goto no_phy;
 	}
@@ -421,7 +492,7 @@
 	if(curphy->init) {
 		err = curphy->init(priv->mii_info);
 
-		if (err) 
+		if (err)
 			goto phy_init_fail;
 	}
 
@@ -446,14 +517,14 @@
 	gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR);
 
 	/* Init hash registers to zero */
-	gfar_write(&priv->regs->iaddr0, 0);
-	gfar_write(&priv->regs->iaddr1, 0);
-	gfar_write(&priv->regs->iaddr2, 0);
-	gfar_write(&priv->regs->iaddr3, 0);
-	gfar_write(&priv->regs->iaddr4, 0);
-	gfar_write(&priv->regs->iaddr5, 0);
-	gfar_write(&priv->regs->iaddr6, 0);
-	gfar_write(&priv->regs->iaddr7, 0);
+	gfar_write(&priv->regs->igaddr0, 0);
+	gfar_write(&priv->regs->igaddr1, 0);
+	gfar_write(&priv->regs->igaddr2, 0);
+	gfar_write(&priv->regs->igaddr3, 0);
+	gfar_write(&priv->regs->igaddr4, 0);
+	gfar_write(&priv->regs->igaddr5, 0);
+	gfar_write(&priv->regs->igaddr6, 0);
+	gfar_write(&priv->regs->igaddr7, 0);
 
 	gfar_write(&priv->regs->gaddr0, 0);
 	gfar_write(&priv->regs->gaddr1, 0);
@@ -464,9 +535,6 @@
 	gfar_write(&priv->regs->gaddr6, 0);
 	gfar_write(&priv->regs->gaddr7, 0);
 
-	/* Zero out rctrl */
-	gfar_write(&priv->regs->rctrl, 0x00000000);
-
 	/* Zero out the rmon mib registers if it has them */
 	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
 		memset((void *) &(priv->regs->rmon), 0,
@@ -497,20 +565,14 @@
 	gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
 }
 
-void stop_gfar(struct net_device *dev)
+
+/* Halt the receive and transmit queues */
+void gfar_halt(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar *regs = priv->regs;
-	unsigned long flags;
 	u32 tempval;
 
-	/* Lock it down */
-	spin_lock_irqsave(&priv->lock, flags);
-
-	/* Tell the kernel the link is down */
-	priv->mii_info->link = 0;
-	adjust_link(dev);
-
 	/* Mask all interrupts */
 	gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
@@ -533,13 +595,29 @@
 	tempval = gfar_read(&regs->maccfg1);
 	tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
 	gfar_write(&regs->maccfg1, tempval);
+}
+
+void stop_gfar(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar *regs = priv->regs;
+	unsigned long flags;
+
+	/* Lock it down */
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* Tell the kernel the link is down */
+	priv->mii_info->link = 0;
+	adjust_link(dev);
+
+	gfar_halt(dev);
 
 	if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
 		/* Clear any pending interrupts */
 		mii_clear_phy_interrupt(priv->mii_info);
 
 		/* Disable PHY Interrupts */
-		mii_configure_phy_interrupt(priv->mii_info, 
+		mii_configure_phy_interrupt(priv->mii_info,
 				MII_INTERRUPT_DISABLED);
 	}
 
@@ -566,7 +644,7 @@
 			sizeof(struct txbd8)*priv->tx_ring_size
 			+ sizeof(struct rxbd8)*priv->rx_ring_size,
 			priv->tx_bd_base,
-			gfar_read(&regs->tbase));
+			gfar_read(&regs->tbase0));
 }
 
 /* If there are any tx skbs or rx skbs still around, free them.
@@ -620,6 +698,34 @@
 	}
 }
 
+void gfar_start(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar *regs = priv->regs;
+	u32 tempval;
+
+	/* Enable Rx and Tx in MACCFG1 */
+	tempval = gfar_read(&regs->maccfg1);
+	tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+	gfar_write(&regs->maccfg1, tempval);
+
+	/* Initialize DMACTRL to have WWR and WOP */
+	tempval = gfar_read(&priv->regs->dmactrl);
+	tempval |= DMACTRL_INIT_SETTINGS;
+	gfar_write(&priv->regs->dmactrl, tempval);
+
+	/* Clear THLT, so that the DMA starts polling now */
+	gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+
+	/* Make sure we aren't stopped */
+	tempval = gfar_read(&priv->regs->dmactrl);
+	tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
+	gfar_write(&priv->regs->dmactrl, tempval);
+
+	/* Unmask the interrupts we look for */
+	gfar_write(&regs->imask, IMASK_DEFAULT);
+}
+
 /* Bring the controller up and running */
 int startup_gfar(struct net_device *dev)
 {
@@ -630,33 +736,34 @@
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar *regs = priv->regs;
-	u32 tempval;
 	int err = 0;
+	u32 rctrl = 0;
 
 	gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
 	/* Allocate memory for the buffer descriptors */
-	vaddr = (unsigned long) dma_alloc_coherent(NULL, 
+	vaddr = (unsigned long) dma_alloc_coherent(NULL,
 			sizeof (struct txbd8) * priv->tx_ring_size +
 			sizeof (struct rxbd8) * priv->rx_ring_size,
 			&addr, GFP_KERNEL);
 
 	if (vaddr == 0) {
-		printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
-		       dev->name);
+		if (netif_msg_ifup(priv))
+			printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
+					dev->name);
 		return -ENOMEM;
 	}
 
 	priv->tx_bd_base = (struct txbd8 *) vaddr;
 
 	/* enet DMA only understands physical addresses */
-	gfar_write(&regs->tbase, addr);
+	gfar_write(&regs->tbase0, addr);
 
 	/* Start the rx descriptor ring where the tx ring leaves off */
 	addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
 	vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
 	priv->rx_bd_base = (struct rxbd8 *) vaddr;
-	gfar_write(&regs->rbase, addr);
+	gfar_write(&regs->rbase0, addr);
 
 	/* Setup the skbuff rings */
 	priv->tx_skbuff =
@@ -664,8 +771,9 @@
 					priv->tx_ring_size, GFP_KERNEL);
 
 	if (priv->tx_skbuff == NULL) {
-		printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
-		       dev->name);
+		if (netif_msg_ifup(priv))
+			printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
+					dev->name);
 		err = -ENOMEM;
 		goto tx_skb_fail;
 	}
@@ -678,8 +786,9 @@
 					priv->rx_ring_size, GFP_KERNEL);
 
 	if (priv->rx_skbuff == NULL) {
-		printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
-		       dev->name);
+		if (netif_msg_ifup(priv))
+			printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
+					dev->name);
 		err = -ENOMEM;
 		goto rx_skb_fail;
 	}
@@ -726,12 +835,13 @@
 	/* If the device has multiple interrupts, register for
 	 * them.  Otherwise, only register for the one */
 	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-		/* Install our interrupt handlers for Error, 
+		/* Install our interrupt handlers for Error,
 		 * Transmit, and Receive */
 		if (request_irq(priv->interruptError, gfar_error,
 				0, "enet_error", dev) < 0) {
-			printk(KERN_ERR "%s: Can't get IRQ %d\n",
-			       dev->name, priv->interruptError);
+			if (netif_msg_intr(priv))
+				printk(KERN_ERR "%s: Can't get IRQ %d\n",
+					dev->name, priv->interruptError);
 
 			err = -1;
 			goto err_irq_fail;
@@ -739,8 +849,9 @@
 
 		if (request_irq(priv->interruptTransmit, gfar_transmit,
 				0, "enet_tx", dev) < 0) {
-			printk(KERN_ERR "%s: Can't get IRQ %d\n",
-			       dev->name, priv->interruptTransmit);
+			if (netif_msg_intr(priv))
+				printk(KERN_ERR "%s: Can't get IRQ %d\n",
+					dev->name, priv->interruptTransmit);
 
 			err = -1;
 
@@ -749,8 +860,9 @@
 
 		if (request_irq(priv->interruptReceive, gfar_receive,
 				0, "enet_rx", dev) < 0) {
-			printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
-			       dev->name, priv->interruptReceive);
+			if (netif_msg_intr(priv))
+				printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
+						dev->name, priv->interruptReceive);
 
 			err = -1;
 			goto rx_irq_fail;
@@ -758,8 +870,9 @@
 	} else {
 		if (request_irq(priv->interruptTransmit, gfar_interrupt,
 				0, "gfar_interrupt", dev) < 0) {
-			printk(KERN_ERR "%s: Can't get IRQ %d\n",
-			       dev->name, priv->interruptError);
+			if (netif_msg_intr(priv))
+				printk(KERN_ERR "%s: Can't get IRQ %d\n",
+					dev->name, priv->interruptError);
 
 			err = -1;
 			goto err_irq_fail;
@@ -787,28 +900,22 @@
 	else
 		gfar_write(&regs->rxic, 0);
 
-	init_waitqueue_head(&priv->rxcleanupq);
+	if (priv->rx_csum_enable)
+		rctrl |= RCTRL_CHECKSUMMING;
 
-	/* Enable Rx and Tx in MACCFG1 */
-	tempval = gfar_read(&regs->maccfg1);
-	tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
-	gfar_write(&regs->maccfg1, tempval);
+	if (priv->extended_hash)
+		rctrl |= RCTRL_EXTHASH;
 
-	/* Initialize DMACTRL to have WWR and WOP */
-	tempval = gfar_read(&priv->regs->dmactrl);
-	tempval |= DMACTRL_INIT_SETTINGS;
-	gfar_write(&priv->regs->dmactrl, tempval);
+	if (priv->vlan_enable)
+		rctrl |= RCTRL_VLAN;
 
-	/* Clear THLT, so that the DMA starts polling now */
-	gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+	/* Init rctrl based on our settings */
+	gfar_write(&priv->regs->rctrl, rctrl);
 
-	/* Make sure we aren't stopped */
-	tempval = gfar_read(&priv->regs->dmactrl);
-	tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-	gfar_write(&priv->regs->dmactrl, tempval);
+	if (dev->features & NETIF_F_IP_CSUM)
+		gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
 
-	/* Unmask the interrupts we look for */
-	gfar_write(&regs->imask, IMASK_DEFAULT);
+	gfar_start(dev);
 
 	return 0;
 
@@ -824,7 +931,7 @@
 			sizeof(struct txbd8)*priv->tx_ring_size
 			+ sizeof(struct rxbd8)*priv->rx_ring_size,
 			priv->tx_bd_base,
-			gfar_read(&regs->tbase));
+			gfar_read(&regs->tbase0));
 
 	if (priv->mii_info->phyinfo->close)
 		priv->mii_info->phyinfo->close(priv->mii_info);
@@ -857,11 +964,62 @@
 	return err;
 }
 
+static struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
+{
+	struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
+
+	memset(fcb, 0, GMAC_FCB_LEN);
+
+	/* Flag the bd so the controller looks for the FCB */
+	bdp->status |= TXBD_TOE;
+
+	return fcb;
+}
+
+static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
+{
+	int len;
+
+	/* If we're here, it's a IP packet with a TCP or UDP
+	 * payload.  We set it to checksum, using a pseudo-header
+	 * we provide
+	 */
+	fcb->ip = 1;
+	fcb->tup = 1;
+	fcb->ctu = 1;
+	fcb->nph = 1;
+
+	/* Notify the controller what the protocol is */
+	if (skb->nh.iph->protocol == IPPROTO_UDP)
+		fcb->udp = 1;
+
+	/* l3os is the distance between the start of the
+	 * frame (skb->data) and the start of the IP hdr.
+	 * l4os is the distance between the start of the
+	 * l3 hdr and the l4 hdr */
+	fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
+	fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+
+	len = skb->nh.iph->tot_len - fcb->l4os;
+
+	/* Provide the pseudoheader csum */
+	fcb->phcs = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+			skb->nh.iph->daddr, len,
+			skb->nh.iph->protocol, 0);
+}
+
+void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
+{
+	fcb->vln = 1;
+	fcb->vlctl = vlan_tx_tag_get(skb);
+}
+
 /* This is called by the kernel when a frame is ready for transmission. */
 /* It is pointed to by the dev->hard_start_xmit function pointer */
 static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct txfcb *fcb = NULL;
 	struct txbd8 *txbdp;
 
 	/* Update transmit stats */
@@ -876,9 +1034,24 @@
 	/* Clear all but the WRAP status flags */
 	txbdp->status &= TXBD_WRAP;
 
+	/* Set up checksumming */
+	if ((dev->features & NETIF_F_IP_CSUM) 
+			&& (CHECKSUM_HW == skb->ip_summed)) {
+		fcb = gfar_add_fcb(skb, txbdp);
+		gfar_tx_checksum(skb, fcb);
+	}
+
+	if (priv->vlan_enable &&
+			unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
+		if (NULL == fcb)
+			fcb = gfar_add_fcb(skb, txbdp);
+
+		gfar_tx_vlan(skb, fcb);
+	}
+
 	/* Set buffer length and pointer */
 	txbdp->length = skb->len;
-	txbdp->bufPtr = dma_map_single(NULL, skb->data, 
+	txbdp->bufPtr = dma_map_single(NULL, skb->data,
 			skb->len, DMA_TO_DEVICE);
 
 	/* Save the skb pointer so we can free it later */
@@ -972,15 +1145,78 @@
 }
 
 
+/* Enables and disables VLAN insertion/extraction */
+static void gfar_vlan_rx_register(struct net_device *dev,
+		struct vlan_group *grp)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	u32 tempval;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	priv->vlgrp = grp;
+
+	if (grp) {
+		/* Enable VLAN tag insertion */
+		tempval = gfar_read(&priv->regs->tctrl);
+		tempval |= TCTRL_VLINS;
+
+		gfar_write(&priv->regs->tctrl, tempval);
+		
+		/* Enable VLAN tag extraction */
+		tempval = gfar_read(&priv->regs->rctrl);
+		tempval |= RCTRL_VLEX;
+		gfar_write(&priv->regs->rctrl, tempval);
+	} else {
+		/* Disable VLAN tag insertion */
+		tempval = gfar_read(&priv->regs->tctrl);
+		tempval &= ~TCTRL_VLINS;
+		gfar_write(&priv->regs->tctrl, tempval);
+
+		/* Disable VLAN tag extraction */
+		tempval = gfar_read(&priv->regs->rctrl);
+		tempval &= ~RCTRL_VLEX;
+		gfar_write(&priv->regs->rctrl, tempval);
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->vlgrp)
+		priv->vlgrp->vlan_devices[vid] = NULL;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
 static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 {
 	int tempsize, tempval;
 	struct gfar_private *priv = netdev_priv(dev);
 	int oldsize = priv->rx_buffer_size;
-	int frame_size = new_mtu + 18;
+	int frame_size = new_mtu + ETH_HLEN;
+
+	if (priv->vlan_enable)
+		frame_size += VLAN_ETH_HLEN;
+
+	if (gfar_uses_fcb(priv))
+		frame_size += GMAC_FCB_LEN;
+
+	frame_size += priv->padding;
 
 	if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
-		printk(KERN_ERR "%s: Invalid MTU setting\n", dev->name);
+		if (netif_msg_drv(priv))
+			printk(KERN_ERR "%s: Invalid MTU setting\n",
+					dev->name);
 		return -EINVAL;
 	}
 
@@ -1120,7 +1356,7 @@
 	skb->dev = dev;
 
 	bdp->bufPtr = dma_map_single(NULL, skb->data,
-			priv->rx_buffer_size + RXBUF_ALIGNMENT, 
+			priv->rx_buffer_size + RXBUF_ALIGNMENT,
 			DMA_FROM_DEVICE);
 
 	bdp->length = 0;
@@ -1190,11 +1426,10 @@
 
 		__netif_rx_schedule(dev);
 	} else {
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
-		       dev->name, gfar_read(&priv->regs->ievent),
-		       gfar_read(&priv->regs->imask));
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
+				dev->name, gfar_read(&priv->regs->ievent),
+				gfar_read(&priv->regs->imask));
 	}
 #else
 
@@ -1209,15 +1444,43 @@
 	else
 		gfar_write(&priv->regs->rxic, 0);
 
-	/* Just in case we need to wake the ring param changer */
-	priv->rxclean = 1;
-
 	spin_unlock(&priv->lock);
 #endif
 
 	return IRQ_HANDLED;
 }
 
+static inline int gfar_rx_vlan(struct sk_buff *skb,
+		struct vlan_group *vlgrp, unsigned short vlctl)
+{
+#ifdef CONFIG_GFAR_NAPI
+	return vlan_hwaccel_receive_skb(skb, vlgrp, vlctl);
+#else
+	return vlan_hwaccel_rx(skb, vlgrp, vlctl);
+#endif
+}
+
+static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
+{
+	/* If valid headers were found, and valid sums
+	 * were verified, then we tell the kernel that no
+	 * checksumming is necessary.  Otherwise, it is */
+	if (fcb->cip && !fcb->eip && fcb->ctu && !fcb->etu)
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	else
+		skb->ip_summed = CHECKSUM_NONE;
+}
+
+
+static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
+{
+	struct rxfcb *fcb = (struct rxfcb *)skb->data;
+
+	/* Remove the FCB from the skb */
+	skb_pull(skb, GMAC_FCB_LEN);
+
+	return fcb;
+}
 
 /* gfar_process_frame() -- handle one incoming packet if skb
  * isn't NULL.  */
@@ -1225,35 +1488,51 @@
 		int length)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct rxfcb *fcb = NULL;
 
 	if (skb == NULL) {
-#ifdef BRIEF_GFAR_ERRORS
-		printk(KERN_WARNING "%s: Missing skb!!.\n",
-				dev->name);
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
 		priv->stats.rx_dropped++;
 		priv->extra_stats.rx_skbmissing++;
 	} else {
+		int ret;
+
 		/* Prep the skb for the packet */
 		skb_put(skb, length);
 
+		/* Grab the FCB if there is one */
+		if (gfar_uses_fcb(priv))
+			fcb = gfar_get_fcb(skb);
+
+		/* Remove the padded bytes, if there are any */
+		if (priv->padding)
+			skb_pull(skb, priv->padding);
+
+		if (priv->rx_csum_enable)
+			gfar_rx_checksum(skb, fcb);
+
 		/* Tell the skb what kind of packet this is */
 		skb->protocol = eth_type_trans(skb, dev);
 
 		/* Send the packet up the stack */
-		if (RECEIVE(skb) == NET_RX_DROP) {
+		if (unlikely(priv->vlgrp && fcb->vln))
+			ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
+		else
+			ret = RECEIVE(skb);
+
+		if (NET_RX_DROP == ret)
 			priv->extra_stats.kernel_dropped++;
-		}
 	}
 
 	return 0;
 }
 
 /* gfar_clean_rx_ring() -- Processes each frame in the rx ring
- *   until the budget/quota has been reached. Returns the number 
+ *   until the budget/quota has been reached. Returns the number
  *   of frames handled
  */
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 {
 	struct rxbd8 *bdp;
 	struct sk_buff *skb;
@@ -1355,9 +1634,6 @@
 				   mk_ic_value(priv->rxcount, priv->rxtime));
 		else
 			gfar_write(&priv->regs->rxic, 0);
-
-		/* Signal to the ring size changer that it's safe to go */
-		priv->rxclean = 1;
 	}
 
 	return (rx_work_limit < 0) ? 1 : 0;
@@ -1393,10 +1669,8 @@
 		if (events & IEVENT_CRL)
 			priv->stats.tx_aborted_errors++;
 		if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
-			printk(KERN_WARNING "%s: tx underrun. dropped packet\n",
-			       dev->name);
-#endif
+			if (netif_msg_tx_err(priv))
+				printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name);
 			priv->stats.tx_dropped++;
 			priv->extra_stats.tx_underrun++;
 
@@ -1415,36 +1689,30 @@
 		gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
 #endif
 
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
-		       gfar_read(&priv->regs->rstat));
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+					dev->name,
+					gfar_read(&priv->regs->rstat));
 	}
 	if (events & IEVENT_BABR) {
 		priv->stats.rx_errors++;
 		priv->extra_stats.rx_babr++;
 
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_DEBUG "%s: babbling error\n", dev->name);
 	}
 	if (events & IEVENT_EBERR) {
 		priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_DEBUG "%s: EBERR\n", dev->name);
 	}
-	if (events & IEVENT_RXC) {
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
-	}
+	if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
+			printk(KERN_DEBUG "%s: control frame\n", dev->name);
 
 	if (events & IEVENT_BABT) {
 		priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_DEBUG "%s: babt error\n", dev->name);
 	}
 
 	return IRQ_HANDLED;
@@ -1510,7 +1778,7 @@
  * If, after GFAR_AN_TIMEOUT seconds, it has not
  * finished, we switch to forced.
  * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to 
+ * request the interrupt, or switch the timer over to
  * using gfar_phy_timer to check status */
 static void gfar_phy_startup_timer(unsigned long data)
 {
@@ -1535,8 +1803,9 @@
 
 		/* Forcing failed!  Give up */
 		if(result) {
-			printk(KERN_ERR "%s: Forcing failed!\n",
-					mii_info->dev->name);
+			if (netif_msg_link(priv))
+				printk(KERN_ERR "%s: Forcing failed!\n",
+						mii_info->dev->name);
 			return;
 		}
 	}
@@ -1546,16 +1815,17 @@
 
 	/* Grab the PHY interrupt, if necessary/possible */
 	if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
-		if (request_irq(priv->einfo->interruptPHY, 
+		if (request_irq(priv->einfo->interruptPHY,
 					phy_interrupt,
-					SA_SHIRQ, 
-					"phy_interrupt", 
+					SA_SHIRQ,
+					"phy_interrupt",
 					mii_info->dev) < 0) {
-			printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
-					mii_info->dev->name,
+			if (netif_msg_intr(priv))
+				printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
+						mii_info->dev->name,
 					priv->einfo->interruptPHY);
 		} else {
-			mii_configure_phy_interrupt(priv->mii_info, 
+			mii_configure_phy_interrupt(priv->mii_info,
 					MII_INTERRUPT_ENABLED);
 			return;
 		}
@@ -1592,15 +1862,17 @@
 				tempval &= ~(MACCFG2_FULL_DUPLEX);
 				gfar_write(&regs->maccfg2, tempval);
 
-				printk(KERN_INFO "%s: Half Duplex\n",
-				       dev->name);
+				if (netif_msg_link(priv))
+					printk(KERN_INFO "%s: Half Duplex\n",
+							dev->name);
 			} else {
 				tempval = gfar_read(&regs->maccfg2);
 				tempval |= MACCFG2_FULL_DUPLEX;
 				gfar_write(&regs->maccfg2, tempval);
 
-				printk(KERN_INFO "%s: Full Duplex\n",
-				       dev->name);
+				if (netif_msg_link(priv))
+					printk(KERN_INFO "%s: Full Duplex\n",
+							dev->name);
 			}
 
 			priv->oldduplex = mii_info->duplex;
@@ -1622,27 +1894,32 @@
 				gfar_write(&regs->maccfg2, tempval);
 				break;
 			default:
-				printk(KERN_WARNING
-				       "%s: Ack!  Speed (%d) is not 10/100/1000!\n",
-				       dev->name, mii_info->speed);
+				if (netif_msg_link(priv))
+					printk(KERN_WARNING
+							"%s: Ack!  Speed (%d) is not 10/100/1000!\n",
+							dev->name, mii_info->speed);
 				break;
 			}
 
-			printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
-			       mii_info->speed);
+			if (netif_msg_link(priv))
+				printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
+						mii_info->speed);
 
 			priv->oldspeed = mii_info->speed;
 		}
 
 		if (!priv->oldlink) {
-			printk(KERN_INFO "%s: Link is up\n", dev->name);
+			if (netif_msg_link(priv))
+				printk(KERN_INFO "%s: Link is up\n", dev->name);
 			priv->oldlink = 1;
 			netif_carrier_on(dev);
 			netif_schedule(dev);
 		}
 	} else {
 		if (priv->oldlink) {
-			printk(KERN_INFO "%s: Link is down\n", dev->name);
+			if (netif_msg_link(priv))
+				printk(KERN_INFO "%s: Link is down\n",
+						dev->name);
 			priv->oldlink = 0;
 			priv->oldspeed = 0;
 			priv->oldduplex = -1;
@@ -1664,8 +1941,9 @@
 	u32 tempval;
 
 	if(dev->flags & IFF_PROMISC) {
-		printk(KERN_INFO "%s: Entering promiscuous mode.\n",
-				dev->name);
+		if (netif_msg_drv(priv))
+			printk(KERN_INFO "%s: Entering promiscuous mode.\n",
+					dev->name);
 		/* Set RCTRL to PROM */
 		tempval = gfar_read(&regs->rctrl);
 		tempval |= RCTRL_PROM;
@@ -1679,6 +1957,14 @@
 	
 	if(dev->flags & IFF_ALLMULTI) {
 		/* Set the hash to rx all multicast frames */
+		gfar_write(&regs->igaddr0, 0xffffffff);
+		gfar_write(&regs->igaddr1, 0xffffffff);
+		gfar_write(&regs->igaddr2, 0xffffffff);
+		gfar_write(&regs->igaddr3, 0xffffffff);
+		gfar_write(&regs->igaddr4, 0xffffffff);
+		gfar_write(&regs->igaddr5, 0xffffffff);
+		gfar_write(&regs->igaddr6, 0xffffffff);
+		gfar_write(&regs->igaddr7, 0xffffffff);
 		gfar_write(&regs->gaddr0, 0xffffffff);
 		gfar_write(&regs->gaddr1, 0xffffffff);
 		gfar_write(&regs->gaddr2, 0xffffffff);
@@ -1689,6 +1975,14 @@
 		gfar_write(&regs->gaddr7, 0xffffffff);
 	} else {
 		/* zero out the hash */
+		gfar_write(&regs->igaddr0, 0x0);
+		gfar_write(&regs->igaddr1, 0x0);
+		gfar_write(&regs->igaddr2, 0x0);
+		gfar_write(&regs->igaddr3, 0x0);
+		gfar_write(&regs->igaddr4, 0x0);
+		gfar_write(&regs->igaddr5, 0x0);
+		gfar_write(&regs->igaddr6, 0x0);
+		gfar_write(&regs->igaddr7, 0x0);
 		gfar_write(&regs->gaddr0, 0x0);
 		gfar_write(&regs->gaddr1, 0x0);
 		gfar_write(&regs->gaddr2, 0x0);
@@ -1727,16 +2021,15 @@
 {
 	u32 tempval;
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar *regs = priv->regs;
-	u32 *hash = &regs->gaddr0;
 	u32 result = ether_crc(MAC_ADDR_LEN, addr);
-	u8 whichreg = ((result >> 29) & 0x7);
-	u8 whichbit = ((result >> 24) & 0x1f);
+	int width = priv->hash_width;
+	u8 whichbit = (result >> (32 - width)) & 0x1f;
+	u8 whichreg = result >> (32 - width + 5);
 	u32 value = (1 << (31-whichbit));
 
-	tempval = gfar_read(&hash[whichreg]);
+	tempval = gfar_read(priv->hash_regs[whichreg]);
 	tempval |= value;
-	gfar_write(&hash[whichreg], tempval);
+	gfar_write(priv->hash_regs[whichreg], tempval);
 
 	return;
 }
@@ -1754,10 +2047,9 @@
 	gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);
 
 	/* Hmm... */
-#if defined (BRIEF_GFAR_ERRORS) || defined (VERBOSE_GFAR_ERRORS)
-	printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
-	       dev->name, events, gfar_read(&priv->regs->imask));
-#endif
+	if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
+		printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
+				dev->name, events, gfar_read(&priv->regs->imask));
 
 	/* Update the error counters */
 	if (events & IEVENT_TXE) {
@@ -1768,19 +2060,17 @@
 		if (events & IEVENT_CRL)
 			priv->stats.tx_aborted_errors++;
 		if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
-			printk(KERN_DEBUG "%s: underrun.  packet dropped.\n",
-			       dev->name);
-#endif
+			if (netif_msg_tx_err(priv))
+				printk(KERN_DEBUG "%s: underrun.  packet dropped.\n",
+						dev->name);
 			priv->stats.tx_dropped++;
 			priv->extra_stats.tx_underrun++;
 
 			/* Reactivate the Tx Queues */
 			gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
 		}
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
-#endif
+		if (netif_msg_tx_err(priv))
+			printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
 	}
 	if (events & IEVENT_BSY) {
 		priv->stats.rx_errors++;
@@ -1793,35 +2083,31 @@
 		gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
 #endif
 
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
-		       gfar_read(&priv->regs->rstat));
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+					dev->name,
+					gfar_read(&priv->regs->rstat));
 	}
 	if (events & IEVENT_BABR) {
 		priv->stats.rx_errors++;
 		priv->extra_stats.rx_babr++;
 
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_DEBUG "%s: babbling error\n", dev->name);
 	}
 	if (events & IEVENT_EBERR) {
 		priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
+		if (netif_msg_rx_err(priv))
+			printk(KERN_DEBUG "%s: EBERR\n", dev->name);
 	}
-	if (events & IEVENT_RXC)
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+	if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
+		if (netif_msg_rx_status(priv))
+			printk(KERN_DEBUG "%s: control frame\n", dev->name);
 
 	if (events & IEVENT_BABT) {
 		priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
-		printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+		if (netif_msg_tx_err(priv))
+			printk(KERN_DEBUG "%s: babt error\n", dev->name);
 	}
 	return IRQ_HANDLED;
 }
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index c2f783a..28af087 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * drivers/net/gianfar.h
  *
  * Gianfar Ethernet Driver
@@ -53,6 +53,12 @@
 /* The maximum number of packets to be handled in one call of gfar_poll */
 #define GFAR_DEV_WEIGHT 64
 
+/* Length for FCB */
+#define GMAC_FCB_LEN 8
+
+/* Default padding amount */
+#define DEFAULT_PADDING 2
+
 /* Number of bytes to align the rx bufs to */
 #define RXBUF_ALIGNMENT 64
 
@@ -91,7 +97,7 @@
 #define JUMBO_FRAME_SIZE 9600
 
 /* Latency of interface clock in nanoseconds */
-/* Interface clock latency , in this case, means the 
+/* Interface clock latency , in this case, means the
  * time described by a value of 1 in the interrupt
  * coalescing registers' time fields.  Since those fields
  * refer to the time it takes for 64 clocks to pass, the
@@ -166,9 +172,28 @@
 				mk_ic_icft(count) | \
 				mk_ic_ictt(time))
 
+#define RCTRL_PAL_MASK		0x001f0000
+#define RCTRL_VLEX		0x00002000
+#define RCTRL_FILREN		0x00001000
+#define RCTRL_GHTX		0x00000400
+#define RCTRL_IPCSEN		0x00000200
+#define RCTRL_TUCSEN		0x00000100
+#define RCTRL_PRSDEP_MASK	0x000000c0
+#define RCTRL_PRSDEP_INIT	0x000000c0
 #define RCTRL_PROM		0x00000008
+#define RCTRL_CHECKSUMMING	(RCTRL_IPCSEN \
+		| RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
+#define RCTRL_EXTHASH		(RCTRL_GHTX)
+#define RCTRL_VLAN		(RCTRL_PRSDEP_INIT)
+
+
 #define RSTAT_CLEAR_RHALT       0x00800000
 
+#define TCTRL_IPCSEN		0x00004000
+#define TCTRL_TUCSEN		0x00002000
+#define TCTRL_VLINS		0x00001000
+#define TCTRL_INIT_CSUM		(TCTRL_TUCSEN | TCTRL_IPCSEN)
+
 #define IEVENT_INIT_CLEAR	0xffffffff
 #define IEVENT_BABR		0x80000000
 #define IEVENT_RXC		0x40000000
@@ -187,12 +212,16 @@
 #define IEVENT_RXB0		0x00008000
 #define IEVENT_GRSC		0x00000100
 #define IEVENT_RXF0		0x00000080
+#define IEVENT_FIR		0x00000008
+#define IEVENT_FIQ		0x00000004
+#define IEVENT_DPE		0x00000002
+#define IEVENT_PERR		0x00000001
 #define IEVENT_RX_MASK          (IEVENT_RXB0 | IEVENT_RXF0)
 #define IEVENT_TX_MASK          (IEVENT_TXB | IEVENT_TXF)
 #define IEVENT_ERR_MASK         \
 (IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
  IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
- | IEVENT_CRL | IEVENT_XFUN)
+ | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR)
 
 #define IMASK_INIT_CLEAR	0x00000000
 #define IMASK_BABR              0x80000000
@@ -212,10 +241,15 @@
 #define IMASK_RXB0              0x00008000
 #define IMASK_GTSC              0x00000100
 #define IMASK_RXFEN0		0x00000080
+#define IMASK_FIR		0x00000008
+#define IMASK_FIQ		0x00000004
+#define IMASK_DPE		0x00000002
+#define IMASK_PERR		0x00000001
 #define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY)
 #define IMASK_DEFAULT  (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
 		IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
-		IMASK_XFUN | IMASK_RXC | IMASK_BABT)
+		IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
+		| IMASK_PERR)
 
 
 /* Attribute fields */
@@ -254,6 +288,18 @@
 #define TXBD_RETRYLIMIT		0x0040
 #define	TXBD_RETRYCOUNTMASK	0x003c
 #define TXBD_UNDERRUN		0x0002
+#define TXBD_TOE		0x0002
+
+/* Tx FCB param bits */
+#define TXFCB_VLN		0x80
+#define TXFCB_IP		0x40
+#define TXFCB_IP6		0x20
+#define TXFCB_TUP		0x10
+#define TXFCB_UDP		0x08
+#define TXFCB_CIP		0x04
+#define TXFCB_CTU		0x02
+#define TXFCB_NPH		0x01
+#define TXFCB_DEFAULT 		(TXFCB_IP|TXFCB_TUP|TXFCB_CTU|TXFCB_NPH)
 
 /* RxBD status field bits */
 #define RXBD_EMPTY		0x8000
@@ -273,6 +319,18 @@
 #define RXBD_TRUNCATED		0x0001
 #define RXBD_STATS		0x01ff
 
+/* Rx FCB status field bits */
+#define RXFCB_VLN		0x8000
+#define RXFCB_IP		0x4000
+#define RXFCB_IP6		0x2000
+#define RXFCB_TUP		0x1000
+#define RXFCB_CIP		0x0800
+#define RXFCB_CTU		0x0400
+#define RXFCB_EIP		0x0200
+#define RXFCB_ETU		0x0100
+#define RXFCB_PERR_MASK		0x000c
+#define RXFCB_PERR_BADL3	0x0008
+
 struct txbd8
 {
 	u16	status;	/* Status Fields */
@@ -280,6 +338,22 @@
 	u32	bufPtr;	/* Buffer Pointer */
 };
 
+struct txfcb {
+	u8	vln:1,
+		ip:1,
+		ip6:1,
+		tup:1,
+		udp:1,
+		cip:1,
+		ctu:1,
+		nph:1;
+	u8	reserved;
+	u8	l4os;	/* Level 4 Header Offset */
+	u8	l3os; 	/* Level 3 Header Offset */
+	u16	phcs;	/* Pseudo-header Checksum */
+	u16	vlctl;	/* VLAN control word */
+};
+
 struct rxbd8
 {
 	u16	status;	/* Status Fields */
@@ -287,6 +361,21 @@
 	u32	bufPtr;	/* Buffer Pointer */
 };
 
+struct rxfcb {
+	u16	vln:1,
+		ip:1,
+		ip6:1,
+		tup:1,
+		cip:1,
+		ctu:1,
+		eip:1,
+		etu:1;
+	u8	rq;	/* Receive Queue index */
+	u8	pro;	/* Layer 4 Protocol */
+	u16	reserved;
+	u16	vlctl;	/* VLAN control word */
+};
+
 struct rmon_mib
 {
 	u32	tr64;	/* 0x.680 - Transmit and Receive 64-byte Frame Counter */
@@ -371,90 +460,191 @@
 
 
 struct gfar {
-	u8	res1[16];
-	u32	ievent;			/* 0x.010 - Interrupt Event Register */
-	u32	imask;			/* 0x.014 - Interrupt Mask Register */
-	u32	edis;			/* 0x.018 - Error Disabled Register */
+	u32	tsec_id;	/* 0x.000 - Controller ID register */
+	u8	res1[12];
+	u32	ievent;		/* 0x.010 - Interrupt Event Register */
+	u32	imask;		/* 0x.014 - Interrupt Mask Register */
+	u32	edis;		/* 0x.018 - Error Disabled Register */
 	u8	res2[4];
-	u32	ecntrl;			/* 0x.020 - Ethernet Control Register */
-	u32	minflr;			/* 0x.024 - Minimum Frame Length Register */
-	u32	ptv;			/* 0x.028 - Pause Time Value Register */
-	u32	dmactrl;		/* 0x.02c - DMA Control Register */
-	u32	tbipa;			/* 0x.030 - TBI PHY Address Register */
+	u32	ecntrl;		/* 0x.020 - Ethernet Control Register */
+	u32	minflr;		/* 0x.024 - Minimum Frame Length Register */
+	u32	ptv;		/* 0x.028 - Pause Time Value Register */
+	u32	dmactrl;	/* 0x.02c - DMA Control Register */
+	u32	tbipa;		/* 0x.030 - TBI PHY Address Register */
 	u8	res3[88];
-	u32	fifo_tx_thr;		/* 0x.08c - FIFO transmit threshold register */
+	u32	fifo_tx_thr;	/* 0x.08c - FIFO transmit threshold register */
 	u8	res4[8];
-	u32	fifo_tx_starve;		/* 0x.098 - FIFO transmit starve register */
+	u32	fifo_tx_starve;	/* 0x.098 - FIFO transmit starve register */
 	u32	fifo_tx_starve_shutoff;	/* 0x.09c - FIFO transmit starve shutoff register */
-	u8	res5[96];
-	u32	tctrl;			/* 0x.100 - Transmit Control Register */
-	u32	tstat;			/* 0x.104 - Transmit Status Register */
-	u8	res6[4];
-	u32	tbdlen;			/* 0x.10c - Transmit Buffer Descriptor Data Length Register */
-	u32	txic;			/* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
-	u8	res7[16];
-	u32	ctbptr;			/* 0x.124 - Current Transmit Buffer Descriptor Pointer Register */
-	u8	res8[92];
-	u32	tbptr;			/* 0x.184 - Transmit Buffer Descriptor Pointer Low Register */
-	u8	res9[124];
-	u32	tbase;			/* 0x.204 - Transmit Descriptor Base Address Register */
-	u8	res10[168];
-	u32	ostbd;			/* 0x.2b0 - Out-of-Sequence Transmit Buffer Descriptor Register */
-	u32	ostbdp;			/* 0x.2b4 - Out-of-Sequence Transmit Data Buffer Pointer Register */
-	u8	res11[72];
-	u32	rctrl;			/* 0x.300 - Receive Control Register */
-	u32	rstat;			/* 0x.304 - Receive Status Register */
-	u8	res12[4];
-	u32	rbdlen;			/* 0x.30c - RxBD Data Length Register */
-	u32	rxic;			/* 0x.310 - Receive Interrupt Coalescing Configuration Register */
-	u8	res13[16];
-	u32	crbptr;			/* 0x.324 - Current Receive Buffer Descriptor Pointer */
-	u8	res14[24];
-	u32	mrblr;			/* 0x.340 - Maximum Receive Buffer Length Register */
-	u8	res15[64];
-	u32	rbptr;			/* 0x.384 - Receive Buffer Descriptor Pointer */
-	u8	res16[124];
-	u32	rbase;			/* 0x.404 - Receive Descriptor Base Address */
-	u8	res17[248];
-	u32	maccfg1;		/* 0x.500 - MAC Configuration 1 Register */
-	u32	maccfg2;		/* 0x.504 - MAC Configuration 2 Register */
-	u32	ipgifg;			/* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
-	u32	hafdup;			/* 0x.50c - Half Duplex Register */
-	u32	maxfrm;			/* 0x.510 - Maximum Frame Length Register */
+	u8	res5[4];
+	u32	fifo_rx_pause;	/* 0x.0a4 - FIFO receive pause threshold register */
+	u32	fifo_rx_alarm;	/* 0x.0a8 - FIFO receive alarm threshold register */
+	u8	res6[84];
+	u32	tctrl;		/* 0x.100 - Transmit Control Register */
+	u32	tstat;		/* 0x.104 - Transmit Status Register */
+	u32	dfvlan;		/* 0x.108 - Default VLAN Control word */
+	u32	tbdlen;		/* 0x.10c - Transmit Buffer Descriptor Data Length Register */
+	u32	txic;		/* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
+	u32	tqueue;		/* 0x.114 - Transmit queue control register */
+	u8	res7[40];
+	u32	tr03wt;		/* 0x.140 - TxBD Rings 0-3 round-robin weightings */
+	u32	tr47wt;		/* 0x.144 - TxBD Rings 4-7 round-robin weightings */
+	u8	res8[52];
+	u32	tbdbph;		/* 0x.17c - Tx data buffer pointer high */
+	u8	res9a[4];
+	u32	tbptr0;		/* 0x.184 - TxBD Pointer for ring 0 */
+	u8	res9b[4];
+	u32	tbptr1;		/* 0x.18c - TxBD Pointer for ring 1 */
+	u8	res9c[4];
+	u32	tbptr2;		/* 0x.194 - TxBD Pointer for ring 2 */
+	u8	res9d[4];
+	u32	tbptr3;		/* 0x.19c - TxBD Pointer for ring 3 */
+	u8	res9e[4];
+	u32	tbptr4;		/* 0x.1a4 - TxBD Pointer for ring 4 */
+	u8	res9f[4];
+	u32	tbptr5;		/* 0x.1ac - TxBD Pointer for ring 5 */
+	u8	res9g[4];
+	u32	tbptr6;		/* 0x.1b4 - TxBD Pointer for ring 6 */
+	u8	res9h[4];
+	u32	tbptr7;		/* 0x.1bc - TxBD Pointer for ring 7 */
+	u8	res9[64];
+	u32	tbaseh;		/* 0x.200 - TxBD base address high */
+	u32	tbase0;		/* 0x.204 - TxBD Base Address of ring 0 */
+	u8	res10a[4];
+	u32	tbase1;		/* 0x.20c - TxBD Base Address of ring 1 */
+	u8	res10b[4];
+	u32	tbase2;		/* 0x.214 - TxBD Base Address of ring 2 */
+	u8	res10c[4];
+	u32	tbase3;		/* 0x.21c - TxBD Base Address of ring 3 */
+	u8	res10d[4];
+	u32	tbase4;		/* 0x.224 - TxBD Base Address of ring 4 */
+	u8	res10e[4];
+	u32	tbase5;		/* 0x.22c - TxBD Base Address of ring 5 */
+	u8	res10f[4];
+	u32	tbase6;		/* 0x.234 - TxBD Base Address of ring 6 */
+	u8	res10g[4];
+	u32	tbase7;		/* 0x.23c - TxBD Base Address of ring 7 */
+	u8	res10[192];
+	u32	rctrl;		/* 0x.300 - Receive Control Register */
+	u32	rstat;		/* 0x.304 - Receive Status Register */
+	u8	res12[8];
+	u32	rxic;		/* 0x.310 - Receive Interrupt Coalescing Configuration Register */
+	u32	rqueue;		/* 0x.314 - Receive queue control register */
+	u8	res13[24];
+	u32	rbifx;		/* 0x.330 - Receive bit field extract control register */
+	u32	rqfar;		/* 0x.334 - Receive queue filing table address register */
+	u32	rqfcr;		/* 0x.338 - Receive queue filing table control register */
+	u32	rqfpr;		/* 0x.33c - Receive queue filing table property register */
+	u32	mrblr;		/* 0x.340 - Maximum Receive Buffer Length Register */
+	u8	res14[56];
+	u32	rbdbph;		/* 0x.37c - Rx data buffer pointer high */
+	u8	res15a[4];
+	u32	rbptr0;		/* 0x.384 - RxBD pointer for ring 0 */
+	u8	res15b[4];
+	u32	rbptr1;		/* 0x.38c - RxBD pointer for ring 1 */
+	u8	res15c[4];
+	u32	rbptr2;		/* 0x.394 - RxBD pointer for ring 2 */
+	u8	res15d[4];
+	u32	rbptr3;		/* 0x.39c - RxBD pointer for ring 3 */
+	u8	res15e[4];
+	u32	rbptr4;		/* 0x.3a4 - RxBD pointer for ring 4 */
+	u8	res15f[4];
+	u32	rbptr5;		/* 0x.3ac - RxBD pointer for ring 5 */
+	u8	res15g[4];
+	u32	rbptr6;		/* 0x.3b4 - RxBD pointer for ring 6 */
+	u8	res15h[4];
+	u32	rbptr7;		/* 0x.3bc - RxBD pointer for ring 7 */
+	u8	res16[64];
+	u32	rbaseh;		/* 0x.400 - RxBD base address high */
+	u32	rbase0;		/* 0x.404 - RxBD base address of ring 0 */
+	u8	res17a[4];
+	u32	rbase1;		/* 0x.40c - RxBD base address of ring 1 */
+	u8	res17b[4];
+	u32	rbase2;		/* 0x.414 - RxBD base address of ring 2 */
+	u8	res17c[4];
+	u32	rbase3;		/* 0x.41c - RxBD base address of ring 3 */
+	u8	res17d[4];
+	u32	rbase4;		/* 0x.424 - RxBD base address of ring 4 */
+	u8	res17e[4];
+	u32	rbase5;		/* 0x.42c - RxBD base address of ring 5 */
+	u8	res17f[4];
+	u32	rbase6;		/* 0x.434 - RxBD base address of ring 6 */
+	u8	res17g[4];
+	u32	rbase7;		/* 0x.43c - RxBD base address of ring 7 */
+	u8	res17[192];
+	u32	maccfg1;	/* 0x.500 - MAC Configuration 1 Register */
+	u32	maccfg2;	/* 0x.504 - MAC Configuration 2 Register */
+	u32	ipgifg;		/* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
+	u32	hafdup;		/* 0x.50c - Half Duplex Register */
+	u32	maxfrm;		/* 0x.510 - Maximum Frame Length Register */
 	u8	res18[12];
-	u32	miimcfg;		/* 0x.520 - MII Management Configuration Register */
-	u32	miimcom;		/* 0x.524 - MII Management Command Register */
-	u32	miimadd;		/* 0x.528 - MII Management Address Register */
-	u32	miimcon;		/* 0x.52c - MII Management Control Register */
-	u32	miimstat;		/* 0x.530 - MII Management Status Register */
-	u32	miimind;		/* 0x.534 - MII Management Indicator Register */
+	u32	miimcfg;	/* 0x.520 - MII Management Configuration Register */
+	u32	miimcom;	/* 0x.524 - MII Management Command Register */
+	u32	miimadd;	/* 0x.528 - MII Management Address Register */
+	u32	miimcon;	/* 0x.52c - MII Management Control Register */
+	u32	miimstat;	/* 0x.530 - MII Management Status Register */
+	u32	miimind;	/* 0x.534 - MII Management Indicator Register */
 	u8	res19[4];
-	u32	ifstat;			/* 0x.53c - Interface Status Register */
-	u32	macstnaddr1;		/* 0x.540 - Station Address Part 1 Register */
-	u32	macstnaddr2;		/* 0x.544 - Station Address Part 2 Register */
-	u8	res20[312];
-	struct rmon_mib	rmon;
-	u8	res21[192];
-	u32	iaddr0;			/* 0x.800 - Indivdual address register 0 */
-	u32	iaddr1;			/* 0x.804 - Indivdual address register 1 */
-	u32	iaddr2;			/* 0x.808 - Indivdual address register 2 */
-	u32	iaddr3;			/* 0x.80c - Indivdual address register 3 */
-	u32	iaddr4;			/* 0x.810 - Indivdual address register 4 */
-	u32	iaddr5;			/* 0x.814 - Indivdual address register 5 */
-	u32	iaddr6;			/* 0x.818 - Indivdual address register 6 */
-	u32	iaddr7;			/* 0x.81c - Indivdual address register 7 */
+	u32	ifstat;		/* 0x.53c - Interface Status Register */
+	u32	macstnaddr1;	/* 0x.540 - Station Address Part 1 Register */
+	u32	macstnaddr2;	/* 0x.544 - Station Address Part 2 Register */
+	u32	mac01addr1;	/* 0x.548 - MAC exact match address 1, part 1 */
+	u32	mac01addr2;	/* 0x.54c - MAC exact match address 1, part 2 */
+	u32	mac02addr1;	/* 0x.550 - MAC exact match address 2, part 1 */
+	u32	mac02addr2;	/* 0x.554 - MAC exact match address 2, part 2 */
+	u32	mac03addr1;	/* 0x.558 - MAC exact match address 3, part 1 */
+	u32	mac03addr2;	/* 0x.55c - MAC exact match address 3, part 2 */
+	u32	mac04addr1;	/* 0x.560 - MAC exact match address 4, part 1 */
+	u32	mac04addr2;	/* 0x.564 - MAC exact match address 4, part 2 */
+	u32	mac05addr1;	/* 0x.568 - MAC exact match address 5, part 1 */
+	u32	mac05addr2;	/* 0x.56c - MAC exact match address 5, part 2 */
+	u32	mac06addr1;	/* 0x.570 - MAC exact match address 6, part 1 */
+	u32	mac06addr2;	/* 0x.574 - MAC exact match address 6, part 2 */
+	u32	mac07addr1;	/* 0x.578 - MAC exact match address 7, part 1 */
+	u32	mac07addr2;	/* 0x.57c - MAC exact match address 7, part 2 */
+	u32	mac08addr1;	/* 0x.580 - MAC exact match address 8, part 1 */
+	u32	mac08addr2;	/* 0x.584 - MAC exact match address 8, part 2 */
+	u32	mac09addr1;	/* 0x.588 - MAC exact match address 9, part 1 */
+	u32	mac09addr2;	/* 0x.58c - MAC exact match address 9, part 2 */
+	u32	mac10addr1;	/* 0x.590 - MAC exact match address 10, part 1*/
+	u32	mac10addr2;	/* 0x.594 - MAC exact match address 10, part 2*/
+	u32	mac11addr1;	/* 0x.598 - MAC exact match address 11, part 1*/
+	u32	mac11addr2;	/* 0x.59c - MAC exact match address 11, part 2*/
+	u32	mac12addr1;	/* 0x.5a0 - MAC exact match address 12, part 1*/
+	u32	mac12addr2;	/* 0x.5a4 - MAC exact match address 12, part 2*/
+	u32	mac13addr1;	/* 0x.5a8 - MAC exact match address 13, part 1*/
+	u32	mac13addr2;	/* 0x.5ac - MAC exact match address 13, part 2*/
+	u32	mac14addr1;	/* 0x.5b0 - MAC exact match address 14, part 1*/
+	u32	mac14addr2;	/* 0x.5b4 - MAC exact match address 14, part 2*/
+	u32	mac15addr1;	/* 0x.5b8 - MAC exact match address 15, part 1*/
+	u32	mac15addr2;	/* 0x.5bc - MAC exact match address 15, part 2*/
+	u8	res20[192];
+	struct rmon_mib	rmon;	/* 0x.680-0x.73c */
+	u32	rrej;		/* 0x.740 - Receive filer rejected packet counter */
+	u8	res21[188];
+	u32	igaddr0;	/* 0x.800 - Indivdual/Group address register 0*/
+	u32	igaddr1;	/* 0x.804 - Indivdual/Group address register 1*/
+	u32	igaddr2;	/* 0x.808 - Indivdual/Group address register 2*/
+	u32	igaddr3;	/* 0x.80c - Indivdual/Group address register 3*/
+	u32	igaddr4;	/* 0x.810 - Indivdual/Group address register 4*/
+	u32	igaddr5;	/* 0x.814 - Indivdual/Group address register 5*/
+	u32	igaddr6;	/* 0x.818 - Indivdual/Group address register 6*/
+	u32	igaddr7;	/* 0x.81c - Indivdual/Group address register 7*/
 	u8	res22[96];
-	u32	gaddr0;			/* 0x.880 - Global address register 0 */
-	u32	gaddr1;			/* 0x.884 - Global address register 1 */
-	u32	gaddr2;			/* 0x.888 - Global address register 2 */
-	u32	gaddr3;			/* 0x.88c - Global address register 3 */
-	u32	gaddr4;			/* 0x.890 - Global address register 4 */
-	u32	gaddr5;			/* 0x.894 - Global address register 5 */
-	u32	gaddr6;			/* 0x.898 - Global address register 6 */
-	u32	gaddr7;			/* 0x.89c - Global address register 7 */
-	u8	res23[856];
-	u32	attr;			/* 0x.bf8 - Attributes Register */
-	u32	attreli;		/* 0x.bfc - Attributes Extract Length and Extract Index Register */
+	u32	gaddr0;		/* 0x.880 - Group address register 0 */
+	u32	gaddr1;		/* 0x.884 - Group address register 1 */
+	u32	gaddr2;		/* 0x.888 - Group address register 2 */
+	u32	gaddr3;		/* 0x.88c - Group address register 3 */
+	u32	gaddr4;		/* 0x.890 - Group address register 4 */
+	u32	gaddr5;		/* 0x.894 - Group address register 5 */
+	u32	gaddr6;		/* 0x.898 - Group address register 6 */
+	u32	gaddr7;		/* 0x.89c - Group address register 7 */
+	u8	res23a[352];
+	u32	fifocfg;	/* 0x.a00 - FIFO interface config register */
+	u8	res23b[252];
+	u8	res23c[248];
+	u32	attr;		/* 0x.bf8 - Attributes Register */
+	u32	attreli;	/* 0x.bfc - Attributes Extract Length and Extract Index Register */
 	u8	res24[1024];
 
 };
@@ -496,6 +686,8 @@
 	struct txbd8 *cur_tx;	        /* Next free ring entry */
 	struct txbd8 *dirty_tx;		/* The Ring entry to be freed. */
 	struct gfar *regs;	/* Pointer to the GFAR memory mapped Registers */
+	u32 *hash_regs[16];
+	int hash_width;
 	struct gfar *phyregs;
 	struct work_struct tq;
 	struct timer_list phy_info_timer;
@@ -506,9 +698,12 @@
 	unsigned int rx_stash_size;
 	unsigned int tx_ring_size;
 	unsigned int rx_ring_size;
-	wait_queue_head_t rxcleanupq;
-	unsigned int rxclean;
 
+	unsigned char vlan_enable:1,
+		rx_csum_enable:1,
+		extended_hash:1;
+	unsigned short padding;
+	struct vlan_group *vlgrp;
 	/* Info structure initialized by board setup code */
 	unsigned int interruptTransmit;
 	unsigned int interruptReceive;
@@ -519,6 +714,8 @@
 	int oldspeed;
 	int oldduplex;
 	int oldlink;
+
+	uint32_t msg_enable;
 };
 
 extern inline u32 gfar_read(volatile unsigned *addr)
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 28046e9..a451de6 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -46,16 +46,18 @@
 
 extern int startup_gfar(struct net_device *dev);
 extern void stop_gfar(struct net_device *dev);
-extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_start(struct net_device *dev);
+extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
 		     u64 * buf);
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
 
 static char stat_gstrings[][ETH_GSTRING_LEN] = {
 	"rx-dropped-by-kernel",
@@ -118,57 +120,56 @@
 	"tx-fragmented-frames",
 };
 
+/* Fill in a buffer with the strings which correspond to the
+ * stats */
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	
+	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+		memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
+	else
+		memcpy(buf, stat_gstrings,
+				GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+}
+
 /* Fill in an array of 64-bit statistics from various sources.
  * This array will be appended to the end of the ethtool_stats
  * structure, and returned to user space
  */
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
 {
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
-	u32 *rmon = (u32 *) & priv->regs->rmon;
 	u64 *extra = (u64 *) & priv->extra_stats;
-	struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-	for (i = 0; i < GFAR_RMON_LEN; i++) {
-		stats->rmon[i] = (u64) (rmon[i]);
-	}
+	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+		u32 *rmon = (u32 *) & priv->regs->rmon;
+		struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-	for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
-		stats->extra[i] = extra[i];
-	}
+		for (i = 0; i < GFAR_RMON_LEN; i++)
+			stats->rmon[i] = (u64) (rmon[i]);
+
+		for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+			stats->extra[i] = extra[i];
+	} else
+		for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+			buf[i] = extra[i];
 }
 
 /* Returns the number of stats (and their corresponding strings) */
-int gfar_stats_count(struct net_device *dev)
+static int gfar_stats_count(struct net_device *dev)
 {
-	return GFAR_STATS_LEN;
-}
-
-void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf)
-{
-	memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
-}
-
-void gfar_fill_stats_normon(struct net_device *dev, 
-		struct ethtool_stats *dummy, u64 * buf)
-{
-	int i;
 	struct gfar_private *priv = netdev_priv(dev);
-	u64 *extra = (u64 *) & priv->extra_stats;
 
-	for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
-		buf[i] = extra[i];
-	}
+	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+		return GFAR_STATS_LEN;
+	else
+		return GFAR_EXTRA_STATS_LEN;
 }
 
-
-int gfar_stats_count_normon(struct net_device *dev)
-{
-	return GFAR_EXTRA_STATS_LEN;
-}
 /* Fills in the drvinfo structure with some basic info */
-void gfar_gdrvinfo(struct net_device *dev, struct
+static void gfar_gdrvinfo(struct net_device *dev, struct
 	      ethtool_drvinfo *drvinfo)
 {
 	strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
@@ -182,7 +183,7 @@
 }
 
 /* Return the current settings in the ethtool_cmd structure */
-int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	uint gigabit_support = 
@@ -216,13 +217,13 @@
 }
 
 /* Return the length of the register structure */
-int gfar_reglen(struct net_device *dev)
+static int gfar_reglen(struct net_device *dev)
 {
 	return sizeof (struct gfar);
 }
 
 /* Return a dump of the GFAR register space */
-void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
 {
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
@@ -233,13 +234,6 @@
 		buf[i] = theregs[i];
 }
 
-/* Fill in a buffer with the strings which correspond to the
- * stats */
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
-{
-	memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
-}
-
 /* Convert microseconds to ethernet clock ticks, which changes
  * depending on what speed the controller is running at */
 static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
@@ -291,9 +285,12 @@
 
 /* Get the coalescing parameters, and put them in the cvals
  * structure.  */
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	
+	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+		return -EOPNOTSUPP;
 
 	cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
 	cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -337,10 +334,13 @@
  * Both cvals->*_usecs and cvals->*_frames have to be > 0
  * in order for coalescing to be active
  */
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
+	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+		return -EOPNOTSUPP;
+
 	/* Set up rx coalescing */
 	if ((cvals->rx_coalesce_usecs == 0) ||
 	    (cvals->rx_max_coalesced_frames == 0))
@@ -379,7 +379,7 @@
 /* Fills in rvals with the current ring parameters.  Currently,
  * rx, rx_mini, and rx_jumbo rings are the same size, as mini and
  * jumbo are ignored by the driver */
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
@@ -401,9 +401,8 @@
  * necessary so that we don't mess things up while we're in
  * motion.  We wait for the ring to be clean before reallocating
  * the rings. */
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
-	u32 tempval;
 	struct gfar_private *priv = netdev_priv(dev);
 	int err = 0;
 
@@ -425,44 +424,116 @@
 		return -EINVAL;
 	}
 
-	/* Stop the controller so we don't rx any more frames */
-	/* But first, make sure we clear the bits */
-	tempval = gfar_read(&priv->regs->dmactrl);
-	tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-	gfar_write(&priv->regs->dmactrl, tempval);
-
-	tempval = gfar_read(&priv->regs->dmactrl);
-	tempval |= (DMACTRL_GRS | DMACTRL_GTS);
-	gfar_write(&priv->regs->dmactrl, tempval);
-
-	while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
-		cpu_relax();
-
-	/* Note that rx is not clean right now */
-	priv->rxclean = 0;
-
 	if (dev->flags & IFF_UP) {
-		/* Tell the driver to process the rest of the frames */
-		gfar_receive(0, (void *) dev, NULL);
+		unsigned long flags;
 
-		/* Now wait for it to be done */
-		wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
+		/* Halt TX and RX, and process the frames which
+		 * have already been received */
+		spin_lock_irqsave(&priv->lock, flags);
+		gfar_halt(dev);
+		gfar_clean_rx_ring(dev, priv->rx_ring_size);
+		spin_unlock_irqrestore(&priv->lock, flags);
 
-		/* Ok, all packets have been handled.  Now we bring it down,
-		 * change the ring size, and bring it up */
-
+		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
 	}
 
+	/* Change the size */
 	priv->rx_ring_size = rvals->rx_pending;
 	priv->tx_ring_size = rvals->tx_pending;
 
+	/* Rebuild the rings with the new size */
+	if (dev->flags & IFF_UP)
+		err = startup_gfar(dev);
+
+	return err;
+}
+
+static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	int err = 0;
+
+	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+		return -EOPNOTSUPP;
+
+	if (dev->flags & IFF_UP) {
+		unsigned long flags;
+
+		/* Halt TX and RX, and process the frames which
+		 * have already been received */
+		spin_lock_irqsave(&priv->lock, flags);
+		gfar_halt(dev);
+		gfar_clean_rx_ring(dev, priv->rx_ring_size);
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		/* Now we take down the rings to rebuild them */
+		stop_gfar(dev);
+	}
+
+	priv->rx_csum_enable = data;
+
 	if (dev->flags & IFF_UP)
 		err = startup_gfar(dev);
 
 	return err;
 }
 
+static uint32_t gfar_get_rx_csum(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+
+	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+		return 0;
+
+	return priv->rx_csum_enable;
+}
+
+static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+	unsigned long flags;
+	struct gfar_private *priv = netdev_priv(dev);
+
+	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+		return -EOPNOTSUPP;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	gfar_halt(dev);
+
+	if (data)
+		dev->features |= NETIF_F_IP_CSUM;
+	else
+		dev->features &= ~NETIF_F_IP_CSUM;
+
+	gfar_start(dev);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static uint32_t gfar_get_tx_csum(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+
+	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+		return 0;
+
+	return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+static uint32_t gfar_get_msglevel(struct net_device *dev)
+{       
+	struct gfar_private *priv = netdev_priv(dev);
+	return priv->msg_enable;
+}       
+        
+static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
+{       
+	struct gfar_private *priv = netdev_priv(dev);
+	priv->msg_enable = data;
+}
+
+
 struct ethtool_ops gfar_ethtool_ops = {
 	.get_settings = gfar_gsettings,
 	.get_drvinfo = gfar_gdrvinfo,
@@ -476,52 +547,10 @@
 	.get_strings = gfar_gstrings,
 	.get_stats_count = gfar_stats_count,
 	.get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = {
-	.get_settings = gfar_gsettings,
-	.get_drvinfo = gfar_gdrvinfo,
-	.get_regs_len = gfar_reglen,
-	.get_regs = gfar_get_regs,
-	.get_link = ethtool_op_get_link,
-	.get_ringparam = gfar_gringparam,
-	.set_ringparam = gfar_sringparam,
-	.get_strings = gfar_gstrings_normon,
-	.get_stats_count = gfar_stats_count_normon,
-	.get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops gfar_nocoalesce_ethtool_ops = {
-	.get_settings = gfar_gsettings,
-	.get_drvinfo = gfar_gdrvinfo,
-	.get_regs_len = gfar_reglen,
-	.get_regs = gfar_get_regs,
-	.get_link = ethtool_op_get_link,
-	.get_ringparam = gfar_gringparam,
-	.set_ringparam = gfar_sringparam,
-	.get_strings = gfar_gstrings,
-	.get_stats_count = gfar_stats_count,
-	.get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_ethtool_ops = {
-	.get_settings = gfar_gsettings,
-	.get_drvinfo = gfar_gdrvinfo,
-	.get_regs_len = gfar_reglen,
-	.get_regs = gfar_get_regs,
-	.get_link = ethtool_op_get_link,
-	.get_coalesce = gfar_gcoalesce,
-	.set_coalesce = gfar_scoalesce,
-	.get_ringparam = gfar_gringparam,
-	.set_ringparam = gfar_sringparam,
-	.get_strings = gfar_gstrings_normon,
-	.get_stats_count = gfar_stats_count_normon,
-	.get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops *gfar_op_array[] = {
-	&gfar_ethtool_ops,
-	&gfar_normon_ethtool_ops,
-	&gfar_nocoalesce_ethtool_ops,
-	&gfar_normon_nocoalesce_ethtool_ops
+	.get_rx_csum = gfar_get_rx_csum,
+	.get_tx_csum = gfar_get_tx_csum,
+	.set_rx_csum = gfar_set_rx_csum,
+	.set_tx_csum = gfar_set_tx_csum,
+	.get_msglevel = gfar_get_msglevel,
+	.set_msglevel = gfar_set_msglevel,
 };
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 13f1148..3213f3e 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -850,7 +850,7 @@
     if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
     data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
 
-    schedule_timeout(data * HZ);
+    msleep_interruptible(data * 1000);
     del_timer_sync(&lp->blink_timer);
 
     /* Restore the original value of the bcrs */
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index e15369c..d6388e1 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -90,7 +90,6 @@
 
 
 /* SB1000 hardware routines to be used during open/configuration phases */
-static inline void nicedelay(unsigned long usecs);
 static inline int card_wait_for_busy_clear(const int ioaddr[],
 	const char* name);
 static inline int card_wait_for_ready(const int ioaddr[], const char* name,
@@ -254,13 +253,6 @@
 
 static const int TimeOutJiffies = (875 * HZ) / 100;
 
-static inline void nicedelay(unsigned long usecs)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(HZ);
-	return;
-}
-
 /* Card Wait For Busy Clear (cannot be used during an interrupt) */
 static inline int
 card_wait_for_busy_clear(const int ioaddr[], const char* name)
@@ -475,7 +467,7 @@
 	udelay(1000);
 	outb(0x0, port);
 	inb(port);
-	nicedelay(60000);
+	ssleep(1);
 	outb(0x4, port);
 	inb(port);
 	udelay(1000);
@@ -537,7 +529,7 @@
 	const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00};
 	const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00};
 
-	nicedelay(50000);
+	ssleep(1);
 	if ((status = card_send_command(ioaddr, name, Command0, st)))
 		return status;
 	if ((status = card_send_command(ioaddr, name, Command1, st)))
@@ -944,7 +936,7 @@
 	/* initialize sb1000 */
 	if ((status = sb1000_reset(ioaddr, name)))
 		return status;
-	nicedelay(200000);
+	ssleep(1);
 	if ((status = sb1000_check_CRC(ioaddr, name)))
 		return status;
 
diff --git a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile
index 5f4bb1a..cb23580 100644
--- a/drivers/net/skfp/Makefile
+++ b/drivers/net/skfp/Makefile
@@ -6,8 +6,8 @@
 
 skfp-objs :=  skfddi.o    hwmtm.o    fplustm.o  smt.o      cfm.o     \
               ecm.o       pcmplc.o   pmf.o      queue.o    rmt.o     \
-	      smtdef.o    smtinit.o  smttimer.o srf.o      smtparse.o\
-	      hwt.o      drvfbi.o   ess.o
+	      smtdef.o    smtinit.o  smttimer.o srf.o      hwt.o     \
+	      drvfbi.o   ess.o
 
 # NOTE:
 #   Compiling this driver produces some warnings (and some more are 
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 052e841..5b47583 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -105,8 +105,8 @@
 #endif
 
 
-/* Prototypes of local functions. */
-void smt_stop_watchdog(struct s_smc *smc);
+/* Prototype of a local function. */
+static void smt_stop_watchdog(struct s_smc *smc);
 
 #ifdef MCA
 static int read_card_id() ;
@@ -631,7 +631,7 @@
  *	LED_Y_OFF	just switch yellow LED off
  *	LED_Y_ON	just switch yello LED on
  */
-void led_indication(struct s_smc *smc, int led_event)
+static void led_indication(struct s_smc *smc, int led_event)
 {
 	/* use smc->hw.mac_ring_is_up == TRUE 
 	 * as indication for Ring Operational
@@ -764,122 +764,6 @@
 #endif
 }
 
-/*--------------------------- DMA init ----------------------------*/
-#ifdef	ISA
-
-/*
- * init DMA
- */
-void init_dma(struct s_smc *smc, int dma)
-{
-	SK_UNUSED(smc) ;
-
-	/*
-	 * set cascade mode,
-	 * clear mask bit (enable DMA cannal)
-	 */
-	if (dma > 3) {
-		outp(0xd6,(dma & 0x03) | 0xc0) ;
-		outp(0xd4, dma & 0x03) ;
-	}
-	else {
-		outp(0x0b,(dma & 0x03) | 0xc0) ;
-		outp(0x0a,dma & 0x03) ;
-	}
-}
-
-/*
- * disable DMA
- */
-void dis_dma(struct s_smc *smc, int dma)
-{
-	SK_UNUSED(smc) ;
-
-	/*
-	 * set mask bit (disable DMA cannal)
-	 */
-	if (dma > 3) {
-		outp(0xd4,(dma & 0x03) | 0x04) ;
-	}
-	else {
-		outp(0x0a,(dma & 0x03) | 0x04) ;
-	}
-}
-
-#endif	/* ISA */
-
-#ifdef	EISA
-
-/*arrays with io addresses of dma controller length and address registers*/
-static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
-static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
-static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
-
-void init_dma(struct s_smc *smc, int dma)
-{
-	/*
-	 * extended mode register
-	 * 32 bit IO
-	 * type c
-	 * TC output
-	 * disable stop
-	 */
-
-	/* mode read (write) demand */
-	smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ;
-	smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ;
-
-	/* 32 bit IO's, burst DMA mode (type "C") */
-	smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ;
-
-	outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ;
-
-	/* disable chaining */
-	outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ;
-
-	/*load dma controller addresses for fast access during set dma*/
-	smc->hw.dma_base_word_count = cntr[smc->hw.dma];
-	smc->hw.dma_base_address = base[smc->hw.dma];
-	smc->hw.dma_base_address_page = page[smc->hw.dma];
-
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-	SK_UNUSED(smc) ;
-
-	outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */
-}
-#endif	/* EISA */
-
-#ifdef	MCA
-void init_dma(struct s_smc *smc, int dma)
-{
-	SK_UNUSED(smc) ;
-	SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-	SK_UNUSED(smc) ;
-	SK_UNUSED(dma) ;
-}
-#endif
-
-#ifdef	PCI
-void init_dma(struct s_smc *smc, int dma)
-{
-	SK_UNUSED(smc) ;
-	SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-	SK_UNUSED(smc) ;
-	SK_UNUSED(dma) ;
-}
-#endif
-
 #ifdef MULT_OEM
 static int is_equal_num(char comp1[], char comp2[], int num)
 {
@@ -1407,7 +1291,7 @@
 #endif	/* DEBUG */
 }
 
-void smt_stop_watchdog(struct s_smc *smc)
+static void smt_stop_watchdog(struct s_smc *smc)
 {
 	SK_UNUSED(smc) ;	/* Make LINT happy. */
 #ifndef	DEBUG
@@ -1422,104 +1306,6 @@
 }
 
 #ifdef	PCI
-static char get_rom_byte(struct s_smc *smc, u_short addr)
-{
-	GET_PAGE(addr) ;
-	return (READ_PROM(ADDR(B2_FDP))) ;
-}
-
-/*
- * ROM image defines
- */
-#define	ROM_SIG_1	0
-#define ROM_SIG_2	1
-#define PCI_DATA_1	0x18
-#define PCI_DATA_2	0x19
-
-/*
- * PCI data structure defines
- */
-#define	VPD_DATA_1	0x08
-#define	VPD_DATA_2	0x09
-#define IMAGE_LEN_1	0x10
-#define IMAGE_LEN_2	0x11
-#define	CODE_TYPE	0x14
-#define	INDICATOR	0x15
-
-/*
- *	BEGIN_MANUAL_ENTRY(mac_drv_vpd_read)
- *	mac_drv_vpd_read(smc,buf,size,image)
- *
- * function	DOWNCALL	(FDDIWARE)
- *		reads the VPD data of the FPROM and writes it into the
- *		buffer
- *
- * para	buf	points to the buffer for the VPD data
- *	size	size of the VPD data buffer
- *	image	boot image; code type of the boot image
- *		image = 0	Intel x86, PC-AT compatible
- *			1	OPENBOOT standard for PCI
- *			2-FF	reserved
- *
- * returns	len	number of VPD data bytes read form the FPROM
- *		<0	number of read bytes
- *		>0	error: data invalid
- *
- *	END_MANUAL_ENTRY
- */
-int mac_drv_vpd_read(struct s_smc *smc, char *buf, int size, char image)
-{
-	u_short	ibase ;
-	u_short pci_base ;
-	u_short vpd ;
-	int	len ;
-
-	len = 0 ;
-	ibase = 0 ;
-	/*
-	 * as long images defined
-	 */
-	while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 &&
-		(u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) {
-		/*
-		 * get the pointer to the PCI data structure
-		 */
-		pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) +
-				(get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ;
-
-		if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) {
-			/*
-			 * we have the right image, read the VPD data
-			 */
-			vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) +
-				(get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ;
-			if (vpd == ibase) {
-				break ;		/* no VPD data */
-			}
-			for (len = 0; len < size; len++,buf++,vpd++) {
-				*buf = get_rom_byte(smc,vpd) ;
-			}
-			break ;
-		}
-		else {
-			/*
-			 * try the next image
-			 */
-			if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) {
-				break ;		/* this was the last image */
-			}
-			ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) +
-				(get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ;
-		}
-	}
-
-	return(len) ;
-}
-
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value)
-{
-	smc->hw.pci_fix_value = fix_value ;
-}
 
 void mac_do_pci_fix(struct s_smc *smc)
 {
diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
index fd39b4b..62b0132 100644
--- a/drivers/net/skfp/ess.c
+++ b/drivers/net/skfp/ess.c
@@ -102,7 +102,7 @@
 void ess_para_change(struct s_smc *smc);
 int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
 			  int fs);
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
 
 
 /*
@@ -375,7 +375,7 @@
  * determines the synchronous bandwidth, set the TSYNC register and the
  * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG.
  */
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
 {
 	/*
 	 * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG,
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index 76e7844..a2ed47f 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -1117,30 +1117,6 @@
 /*
 	BEGIN_MANUAL_ENTRY(if,func;others;2)
 
-	int mac_set_func_addr(smc,f_addr)
-	struct s_smc *smc ;
-	u_long f_addr ;
-
-Function	DOWNCALL	(SMT, fplustm.c)
-		Set a Token-Ring functional address, the address will
-		be activated after calling mac_update_multicast()
-
-Para	f_addr	functional bits in non-canonical format
-
-Returns	0: always success
-
-	END_MANUAL_ENTRY()
- */
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr)
-{
-	smc->hw.fp.func_addr = f_addr ;
-	return(0) ;
-}
-
-
-/*
-	BEGIN_MANUAL_ENTRY(if,func;others;2)
-
 	int mac_add_multicast(smc,addr,can)
 	struct s_smc *smc ;
 	struct fddi_addr *addr ;
@@ -1203,52 +1179,6 @@
 }
 
 /*
-	BEGIN_MANUAL_ENTRY(if,func;others;2)
-
-	void mac_del_multicast(smc,addr,can)
-	struct s_smc *smc ;
-	struct fddi_addr *addr ;
-	int can ;
-
-Function	DOWNCALL	(SMT, fplustm.c)
-		Delete an entry from the multicast table
-
-Para	addr	pointer to a multicast address
-	can	= 0:	the multicast address has the physical format
-		= 1:	the multicast address has the canonical format
-		| 0x80	permanent
-
-	END_MANUAL_ENTRY()
- */
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
-{
-	SK_LOC_DECL(struct fddi_addr,own) ;
-	struct s_fpmc	*tb ;
-
-	if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80)))
-		return ;
-	/*
-	 * permanent addresses must be deleted with perm bit
-	 * and vice versa
-	 */
-	if (( tb->perm &&  (can & 0x80)) ||
-	    (!tb->perm && !(can & 0x80))) {
-		/*
-		 * delete it
-		 */
-		if (tb->n) {
-			tb->n-- ;
-			if (tb->perm) {
-				smc->hw.fp.smt_slots_used-- ;
-			}
-			else {
-				smc->hw.fp.os_slots_used-- ;
-			}
-		}
-	}
-}
-
-/*
  * mode
  */
 
diff --git a/drivers/net/skfp/h/cmtdef.h b/drivers/net/skfp/h/cmtdef.h
index 603982d..f2f771d 100644
--- a/drivers/net/skfp/h/cmtdef.h
+++ b/drivers/net/skfp/h/cmtdef.h
@@ -507,7 +507,6 @@
 		      int *remote, int *mac);
 void plc_config_mux(struct s_smc *smc, int mux);
 void sm_lem_evaluate(struct s_smc *smc);
-void smt_clear_una_dna(struct s_smc *smc);
 void mac_update_counter(struct s_smc *smc);
 void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off);
 void sm_ma_control(struct s_smc *smc, int mode);
@@ -541,11 +540,9 @@
 u_long smt_get_time(void);
 u_long smt_get_tid(struct s_smc *smc);
 void smt_timer_done(struct s_smc *smc);
-void smt_set_defaults(struct s_smc *smc);
 void smt_fixup_mib(struct s_smc *smc);
 void smt_reset_defaults(struct s_smc *smc, int level);
 void smt_agent_task(struct s_smc *smc);
-void smt_please_reconnect(struct s_smc *smc, int reconn_time);
 int smt_check_para(struct s_smc *smc, struct smt_header *sm,
 		   const u_short list[]);
 void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr);
@@ -568,7 +565,6 @@
 int pcm_rooted_station(struct s_smc *smc);
 int cfm_get_mac_input(struct s_smc *smc);
 int cfm_get_mac_output(struct s_smc *smc);
-int port_to_mib(struct s_smc *smc, int p);
 int cem_build_path(struct s_smc *smc, char *to, int path_index);
 int sm_mac_get_tx_state(struct s_smc *smc);
 char *get_pcmstate(struct s_smc *smc, int np);
@@ -580,8 +576,6 @@
 void smt_set_timestamp(struct s_smc *smc, u_char *p);
 void mac_set_rx_mode(struct s_smc *smc,	int mode);
 int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr);
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
 void mac_update_multicast(struct s_smc *smc);
 void mac_clear_multicast(struct s_smc *smc);
 void set_formac_tsync(struct s_smc *smc, long sync_bw);
@@ -599,7 +593,6 @@
 int smt_set_mac_opvalues(struct s_smc *smc);
 
 #ifdef TAG_MODE
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value);
 void mac_do_pci_fix(struct s_smc *smc);
 void mac_drv_clear_tx_queue(struct s_smc *smc);
 void mac_drv_repair_descr(struct s_smc *smc);
diff --git a/drivers/net/skfp/h/hwmtm.h b/drivers/net/skfp/h/hwmtm.h
index 4e360af..1a606d4 100644
--- a/drivers/net/skfp/h/hwmtm.h
+++ b/drivers/net/skfp/h/hwmtm.h
@@ -262,31 +262,6 @@
 					(smc)->hw.fp.tx_q[queue].tx_curr_put
 
 /*
- *	BEGIN_MANUAL_ENTRY(HWM_TX_CHECK)
- *	void HWM_TX_CHECK(smc,frame_status,low_water)
- *
- * function	MACRO		(hardware module, hwmtm.h)
- *		This macro is invoked by the OS-specific before it left it's
- *		driver_send function. This macro calls mac_drv_clear_txd
- *		if the free TxDs of the current transmit queue is equal or
- *		lower than the given low water mark.
- *
- * para	frame_status	status of the frame, see design description
- *	low_water	low water mark of free TxD's
- *
- *	END_MANUAL_ENTRY
- */
-#ifndef HWM_NO_FLOW_CTL
-#define	HWM_TX_CHECK(smc,frame_status,low_water) {\
-	if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\
-		mac_drv_clear_txd(smc) ;\
-	}\
-}
-#else
-#define	HWM_TX_CHECK(smc,frame_status,low_water)	mac_drv_clear_txd(smc)
-#endif
-
-/*
  *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN)
  *	int HWM_GET_RX_FRAG_LEN(rxd)
  *
diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c
index 18d4290..438f424 100644
--- a/drivers/net/skfp/hwmtm.c
+++ b/drivers/net/skfp/hwmtm.c
@@ -86,6 +86,7 @@
 static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue);
 static SMbuf* get_llc_rx(struct s_smc *smc);
 static SMbuf* get_txd_mb(struct s_smc *smc);
+static void mac_drv_clear_txd(struct s_smc *smc);
 
 /*
 	-------------------------------------------------------------
@@ -146,7 +147,6 @@
 */
 void process_receive(struct s_smc *smc);
 void fddi_isr(struct s_smc *smc);
-void mac_drv_clear_txd(struct s_smc *smc);
 void smt_free_mbuf(struct s_smc *smc, SMbuf *mb);
 void init_driver_fplus(struct s_smc *smc);
 void mac_drv_rx_mode(struct s_smc *smc, int mode);
@@ -158,7 +158,6 @@
 void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
 		 int frame_status);
 
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len);
 int mac_drv_init(struct s_smc *smc);
 int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
 		int frame_status);
@@ -1448,35 +1447,6 @@
 	NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;
 }
 
-#ifndef	NDIS_OS2
-/*
- *	BEGIN_MANUAL_ENTRY(mac_drv_rx_frag)
- *	int mac_drv_rx_frag(smc,virt,len)
- *
- * function	DOWNCALL	(hwmtm.c)
- *		mac_drv_rx_frag fills the fragment with a part of the frame.
- *
- * para	virt	the virtual address of the fragment
- *	len	the length in bytes of the fragment
- *
- * return 0:	success code, no errors possible
- *
- *	END_MANUAL_ENTRY
- */
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len)
-{
-	NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ;
-
-	DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ;
-	memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ;
-	smc->os.hwm.r.mb_pos += len ;
-
-	NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ;
-	return(0) ;
-}
-#endif
-
-
 /*
  *	BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
  *
@@ -1978,7 +1948,7 @@
  *
  *	END_MANUAL_ENTRY
  */
-void mac_drv_clear_txd(struct s_smc *smc)
+static void mac_drv_clear_txd(struct s_smc *smc)
 {
 	struct s_smt_tx_queue *queue ;
 	struct s_smt_fp_txd volatile *t1 ;
diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c
index 571f055..cd0aa4c 100644
--- a/drivers/net/skfp/pcmplc.c
+++ b/drivers/net/skfp/pcmplc.c
@@ -1861,13 +1861,6 @@
 #endif
 }
 
-void pcm_set_lct_short(struct s_smc *smc, int n)
-{
-	if (n <= 0 || n > 1000)
-		return ;
-	smc->s.lct_short = n ;
-}
-
 #ifdef	DEBUG
 /*
  * fill state struct
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
index f2b446d..efc639c 100644
--- a/drivers/net/skfp/pmf.c
+++ b/drivers/net/skfp/pmf.c
@@ -36,12 +36,13 @@
 static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm);
 static const struct s_p_tab* smt_get_ptab(u_short para);
 static int smt_mib_phys(struct s_smc *smc);
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
-		 int set);
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+			int local, int set);
 void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
 		  int index, int local);
 static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req,
 				     int set, int local);
+static int port_to_mib(struct s_smc *smc, int p);
 
 #define MOFFSS(e)	((int)&(((struct fddi_mib *)0)->e))
 #define MOFFSA(e)	((int) (((struct fddi_mib *)0)->e))
@@ -1078,8 +1079,8 @@
 /*
  * set parameter
  */
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
-		 int set)
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+			int local, int set)
 {
 #define IFSET(x)	if (set) (x)
 
@@ -1549,7 +1550,7 @@
 #endif
 }
 
-int port_to_mib(struct s_smc *smc, int p)
+static int port_to_mib(struct s_smc *smc, int p)
 {
 #ifdef	CONCENTRATOR
 	SK_UNUSED(smc) ;
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index c88aad6..4b5ed2c 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -149,7 +149,6 @@
 extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
 extern void mac_drv_clear_rx_queue(struct s_smc *smc);
 extern void enable_tx_irq(struct s_smc *smc, u_short queue);
-extern void mac_drv_clear_txd(struct s_smc *smc);
 
 static struct pci_device_id skfddi_pci_tbl[] = {
 	{ PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, },
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index c3a0d2f..f17c05c 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -110,7 +110,7 @@
 static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed,
 			  int len);
 
-void smt_clear_una_dna(struct s_smc *smc);
+static void smt_clear_una_dna(struct s_smc *smc);
 static void smt_clear_old_una_dna(struct s_smc *smc);
 #ifdef	CONCENTRATOR
 static int entity_to_index(void);
@@ -118,7 +118,7 @@
 static void update_dac(struct s_smc *smc, int report);
 static int div_ratio(u_long upper, u_long lower);
 #ifdef  USE_CAN_ADDR
-void	hwm_conv_can(struct s_smc *smc, char *data, int len);
+static void	hwm_conv_can(struct s_smc *smc, char *data, int len);
 #else
 #define		hwm_conv_can(smc,data,len)
 #endif
@@ -216,24 +216,6 @@
 	DB_SMT("SMT agent task\n",0,0) ;
 }
 
-void smt_please_reconnect(struct s_smc *smc, int reconn_time)
-/* struct s_smc	*smc;  Pointer to SMT context */
-/* int reconn_time;    Wait for reconnect time in seconds */
-{
-	/*
-	 * The please reconnect variable is used as a timer.
-	 * It is decremented each time smt_event is called.
-	 * This happens every second or when smt_force_irq is called.
-	 * Note: smt_force_irq () is called on some packet receives and
-	 *       when a multicast address is changed. Since nothing
-	 *       is received during the disconnect and the multicast
-	 *       address changes can be viewed as not very often and
-	 *       the timer runs out close to its given value
-	 *       (reconn_time).
-	 */
-	smc->sm.please_reconnect = reconn_time ;
-}
-
 #ifndef SMT_REAL_TOKEN_CT
 void smt_emulate_token_ct(struct s_smc *smc, int mac_index)
 {
@@ -1574,7 +1556,7 @@
  * clear DNA and UNA
  * called from CFM if configuration changes
  */
-void smt_clear_una_dna(struct s_smc *smc)
+static void smt_clear_una_dna(struct s_smc *smc)
 {
 	smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
 	smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
@@ -2058,30 +2040,10 @@
 }
 
 /*
- * change tneg
- *	set T_Req in MIB (Path Attribute)
- *	calculate new values for MAC
- *	if change required
- *		disconnect
- *		set reconnect
- *	end
- */
-void smt_change_t_neg(struct s_smc *smc, u_long tneg)
-{
-	smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ;
-
-	if (smt_set_mac_opvalues(smc)) {
-		RS_SET(smc,RS_EVENT) ;
-		smc->sm.please_reconnect = 1 ;
-		queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
-	}
-}
-
-/*
  * canonical conversion of <len> bytes beginning form *data
  */
 #ifdef  USE_CAN_ADDR
-void hwm_conv_can(struct s_smc *smc, char *data, int len)
+static void hwm_conv_can(struct s_smc *smc, char *data, int len)
 {
 	int i ;
 
diff --git a/drivers/net/skfp/smtdef.c b/drivers/net/skfp/smtdef.c
index 5a0c8db..4e07ff7 100644
--- a/drivers/net/skfp/smtdef.c
+++ b/drivers/net/skfp/smtdef.c
@@ -76,11 +76,6 @@
 static void smt_init_mib(struct s_smc *smc, int level);
 static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper);
 
-void smt_set_defaults(struct s_smc *smc)
-{
-	smt_reset_defaults(smc,0) ;
-}
-
 #define MS2BCLK(x)	((x)*12500L)
 #define US2BCLK(x)	((x)*1250L)
 
diff --git a/drivers/net/skfp/smtparse.c b/drivers/net/skfp/smtparse.c
deleted file mode 100644
index d5779e4..0000000
--- a/drivers/net/skfp/smtparse.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/******************************************************************************
- *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- *	See the file "skfddi.c" for further information.
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-
-/*
-	parser for SMT parameters
-*/
-
-#include "h/types.h"
-#include "h/fddi.h"
-#include "h/smc.h"
-#include "h/smt_p.h"
-
-#define KERNEL
-#include "h/smtstate.h"
-
-#ifndef	lint
-static const char ID_sccs[] = "@(#)smtparse.c	1.12 98/10/06 (C) SK " ;
-#endif
-
-#ifdef	sun
-#define _far
-#endif
-
-/*
- * convert to BCLK units
- */
-#define MS2BCLK(x)      ((x)*12500L)
-#define US2BCLK(x)      ((x/10)*125L)
-
-/*
- * parameter table
- */
-static struct s_ptab {
-	char	*pt_name ;
-	u_short	pt_num ;
-	u_short	pt_type ;
-	u_long	pt_min ;
-	u_long	pt_max ;
-} ptab[] = {
-	{ "PMFPASSWD",0,	0 } ,
-	{ "USERDATA",1,		0 } ,
-	{ "LERCUTOFFA",2,	1,	4,	15	} ,
-	{ "LERCUTOFFB",3,	1,	4,	15	} ,
-	{ "LERALARMA",4,	1,	4,	15	} ,
-	{ "LERALARMB",5,	1,	4,	15	} ,
-	{ "TMAX",6,		1,	5,	165	} ,
-	{ "TMIN",7,		1,	5,	165	} ,
-	{ "TREQ",8,		1,	5,	165	} ,
-	{ "TVX",9,		1,	2500,	10000	} ,
-#ifdef ESS
-	{ "SBAPAYLOAD",10,	1,	0,	1562	} ,
-	{ "SBAOVERHEAD",11,	1,	50,	5000	} ,
-	{ "MAXTNEG",12,		1,	5,	165	} ,
-	{ "MINSEGMENTSIZE",13,	1,	0,	4478	} ,
-	{ "SBACATEGORY",14,	1,	0,	0xffff	} ,
-	{ "SYNCHTXMODE",15,	0 } ,
-#endif
-#ifdef SBA
-	{ "SBACOMMAND",16,	0 } ,
-	{ "SBAAVAILABLE",17,	1,	0,	100	} ,
-#endif
-	{ NULL }
-} ;
-
-/* Define maximum string size for values and keybuffer */
-#define MAX_VAL	40
-
-/*
- * local function declarations
- */
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
-			u_long mx, int scale);
-static int parse_word(char *buf, char _far *text);
-
-#ifdef SIM
-#define DB_MAIN(a,b,c)	printf(a,b,c)
-#else
-#define DB_MAIN(a,b,c)
-#endif
-
-/*
- * BEGIN_MANUAL_ENTRY()
- *
- *	int smt_parse_arg(struct s_smc *,char _far *keyword,int type,
-		char _far *value)
- *
- *	parse SMT parameter
- *	*keyword
- *		pointer to keyword, must be \0, \n or \r terminated
- *	*value	pointer to value, either char * or u_long *
- *		if char *
- *			pointer to value, must be \0, \n or \r terminated
- *		if u_long *
- *			contains binary value
- *
- *	type	0: integer
- *		1: string
- *	return
- *		0	parameter parsed ok
- *		!= 0	error
- *	NOTE:
- *		function can be called with DS != SS
- *
- *
- * END_MANUAL_ENTRY()
- */
-int smt_parse_arg(struct s_smc *smc, char _far *keyword, int type,
-		  char _far *value)
-{
-	char		keybuf[MAX_VAL+1];
-	char		valbuf[MAX_VAL+1];
-	char		c ;
-	char 		*p ;
-	char		*v ;
-	char		*d ;
-	u_long		val = 0 ;
-	struct s_ptab	*pt ;
-	int		st ;
-	int		i ;
-
-	/*
-	 * parse keyword
-	 */
-	if ((st = parse_word(keybuf,keyword)))
-		return(st) ;
-	/*
-	 * parse value if given as string
-	 */
-	if (type == 1) {
-		if ((st = parse_word(valbuf,value)))
-			return(st) ;
-	}
-	/*
-	 * search in table
-	 */
-	st = 0 ;
-	for (pt = ptab ; (v = pt->pt_name) ; pt++) {
-		for (p = keybuf ; (c = *p) ; p++,v++) {
-			if (c != *v)
-				break ;
-		}
-		if (!c && !*v)
-			break ;
-	}
-	if (!v)
-		return(-1) ;
-#if	0
-	printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ;
-#endif
-	/*
-	 * set value in MIB
-	 */
-	if (pt->pt_type)
-		val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ;
-	switch (pt->pt_num) {
-	case 0 :
-		v = valbuf ;
-		d = (char *) smc->mib.fddiPRPMFPasswd ;
-		for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++)
-			*d++ = *v++ ;
-		DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ;
-		break ;
-	case 1 :
-		v = valbuf ;
-		d = (char *) smc->mib.fddiSMTUserData ;
-		for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++)
-			*d++ = *v++ ;
-		DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ;
-		break ;
-	case 2 :
-		smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ;
-		DB_MAIN("SET %s = %d\n",
-			pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ;
-		break ;
-	case 3 :
-		smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ;
-		DB_MAIN("SET %s = %d\n",
-			pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ;
-		break ;
-	case 4 :
-		smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ;
-		DB_MAIN("SET %s = %d\n",
-			pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ;
-		break ;
-	case 5 :
-		smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ;
-		DB_MAIN("SET %s = %d\n",
-			pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ;
-		break ;
-	case 6 :			/* TMAX */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		smc->mib.a[PATH0].fddiPATHT_MaxLowerBound =
-			(u_long) -MS2BCLK((long)val) ;
-		break ;
-	case 7 :			/* TMIN */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		smc->mib.m[MAC0].fddiMACT_Min =
-			(u_long) -MS2BCLK((long)val) ;
-		break ;
-	case 8 :			/* TREQ */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		smc->mib.a[PATH0].fddiPATHMaxT_Req =
-			(u_long) -MS2BCLK((long)val) ;
-		break ;
-	case 9 :			/* TVX */
-		DB_MAIN("SET %s = %d \n",pt->pt_name,val) ;
-		smc->mib.a[PATH0].fddiPATHTVXLowerBound =
-			(u_long) -US2BCLK((long)val) ;
-		break ;
-#ifdef	ESS
-	case 10 :			/* SBAPAYLOAD */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		if (smc->mib.fddiESSPayload != val) {
-			smc->ess.raf_act_timer_poll = TRUE ;
-			smc->mib.fddiESSPayload = val ;
-		}
-		break ;
-	case 11 :			/* SBAOVERHEAD */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		smc->mib.fddiESSOverhead = val ;
-		break ;
-	case 12 :			/* MAXTNEG */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ;
-		break ;
-	case 13 :			/* MINSEGMENTSIZE */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		smc->mib.fddiESSMinSegmentSize = val ;
-		break ;
-	case 14 :			/* SBACATEGORY */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		smc->mib.fddiESSCategory =
-			(smc->mib.fddiESSCategory & 0xffff) |
-			((u_long)(val << 16)) ;
-		break ;
-	case 15 :			/* SYNCHTXMODE */
-		/* do not use memcmp(valbuf,"ALL",3) because DS != SS */
-		if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') {
-			smc->mib.fddiESSSynchTxMode = TRUE ;
-			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-		}
-		/* if (!memcmp(valbuf,"SPLIT",5)) { */
-		if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' &&
-			valbuf[3] == 'I' && valbuf[4] == 'T') {
-			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-			smc->mib.fddiESSSynchTxMode = FALSE ;
-		}
-		break ;
-#endif
-#ifdef	SBA
-	case 16 :			/* SBACOMMAND */
-		/* if (!memcmp(valbuf,"START",5)) { */
-		if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' &&
-			valbuf[3] == 'R' && valbuf[4] == 'T') {
-			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-			smc->mib.fddiSBACommand = SB_START ;
-		}
-		/* if (!memcmp(valbuf,"STOP",4)) { */
-		if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' &&
-			valbuf[3] == 'P') {
-			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-			smc->mib.fddiSBACommand = SB_STOP ;
-		}
-		break ;
-	case 17 :			/* SBAAVAILABLE */
-		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-		smc->mib.fddiSBAAvailable = (u_char) val ;
-		break ;
-#endif
-	}
-	return(0) ;
-}
-
-static int parse_word(char *buf, char _far *text)
-{
-	char		c ;
-	char 		*p ;
-	int		p_len ;
-	int		quote ;
-	int		i ;
-	int		ok ;
-
-	/*
-	 * skip leading white space
-	 */
-	p = buf ;
-	for (i = 0 ; i < MAX_VAL ; i++)
-		*p++ = 0 ;
-	p = buf ;
-	p_len = 0 ;
-	ok = 0 ;
-	while ( (c = *text++) && (c != '\n') && (c != '\r')) {
-		if ((c != ' ') && (c != '\t')) {
-			ok = 1 ;
-			break ;
-		}
-	}
-	if (!ok)
-		return(-1) ;
-	if (c == '"') {
-		quote = 1 ;
-	}
-	else {
-		quote = 0 ;
-		text-- ;
-	}
-	/*
-	 * parse valbuf
-	 */
-	ok = 0 ;
-	while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n')
-		&& (c != '\r')) {
-		switch (quote) {
-		case 0 :
-			if ((c == ' ') || (c == '\t') || (c == '=')) {
-				ok = 1 ;
-				break ;
-			}
-			*p++ = c ;
-			p_len++ ;
-			break ;
-		case 2 :
-			*p++ = c ;
-			p_len++ ;
-			quote = 1 ;
-			break ;
-		case 1 :
-			switch (c) {
-			case '"' :
-				ok = 1 ;
-				break ;
-			case '\\' :
-				quote = 2 ;
-				break ;
-			default :
-				*p++ = c ;
-				p_len++ ;
-			}
-		}
-	}
-	*p++ = 0 ;
-	for (p = buf ; (c = *p) ; p++) {
-		if (c >= 'a' && c <= 'z')
-			*p = c + 'A' - 'a' ;
-	}
-	return(0) ;
-}
-
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
-			u_long mx, int scale)
-{
-	u_long	x = 0 ;
-	char	c ;
-
-	if (type == 0) {		/* integer */
-		u_long _far	*l ;
-		u_long		u1 ;
-
-		l = (u_long _far *) value ;
-		u1 = *l ;
-		/*
-		 * if the value is negative take the lower limit
-		 */
-		if ((long)u1 < 0) {
-			if (- ((long)u1) > (long) mx) {
-				u1 = 0 ;
-			}
-			else {
-				u1 = (u_long) - ((long)u1) ;
-			}
-		}
-		x = u1 ;
-	}
-	else {				/* string */
-		int	sign = 0 ;
-
-		if (*v == '-') {
-			sign = 1 ;
-		}
-		while ((c = *v++) && (c >= '0') && (c <= '9')) {
-			x = x * 10 + c - '0' ;
-		}
-		if (scale == 10) {
-			x *= 10 ;
-			if (c == '.') {
-				if ((c = *v++) && (c >= '0') && (c <= '9')) {
-					x += c - '0' ;
-				}
-			}
-		}
-		if (sign)
-			x = (u_long) - ((long)x) ;
-	}
-	/*
-	 * if the value is negative
-	 *	and the absolute value is outside the limits
-	 *		take the lower limit
-	 *	else
-	 *		take the absoute value
-	 */
-	if ((long)x < 0) {
-		if (- ((long)x) > (long) mx) {
-			x = 0 ;
-		}
-		else {
-			x = (u_long) - ((long)x) ;
-		}
-	}
-	if (x < mn)
-		return(mn) ;
-	else if (x > mx)
-		return(mx) ;
-	return(x) ;
-}
-
-#if 0
-struct	s_smc	SMC ;
-main()
-{
-	char	*p ;
-	char	*v ;
-	char	buf[100] ;
-	int	toggle = 0 ;
-
-	while (gets(buf)) {
-		p = buf ;
-		while (*p && ((*p == ' ') || (*p == '\t')))
-			p++ ;
-
-		while (*p && ((*p != ' ') && (*p != '\t')))
-			p++ ;
-
-		v = p ;
-		while (*v && ((*v == ' ') || (*v == '\t')))
-			v++ ;
-		if ((*v >= '0') && (*v <= '9')) {
-			toggle = !toggle ;
-			if (toggle) {
-				u_long	l ;
-				l = atol(v) ;
-				smt_parse_arg(&SMC,buf,0,(char _far *)&l) ;
-			}
-			else
-				smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
-		}
-		else {
-			smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
-		}
-	}
-	exit(0) ;
-}
-#endif
-
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index fd80048..cfb9d3c 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -315,15 +315,25 @@
 	struct smc_local *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
 	unsigned int ctl, cfg;
+	struct sk_buff *pending_skb;
 
 	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
 
-	/* Disable all interrupts */
+	/* Disable all interrupts, block TX tasklet */
 	spin_lock(&lp->lock);
 	SMC_SELECT_BANK(2);
 	SMC_SET_INT_MASK(0);
+	pending_skb = lp->pending_tx_skb;
+	lp->pending_tx_skb = NULL;
 	spin_unlock(&lp->lock);
 
+	/* free any pending tx skb */
+	if (pending_skb) {
+		dev_kfree_skb(pending_skb);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
+	}
+
 	/*
 	 * This resets the registers mostly to defaults, but doesn't
 	 * affect EEPROM.  That seems unnecessary
@@ -389,14 +399,6 @@
 	SMC_SELECT_BANK(2);
 	SMC_SET_MMU_CMD(MC_RESET);
 	SMC_WAIT_MMU_BUSY();
-
-	/* clear anything saved */
-	if (lp->pending_tx_skb != NULL) {
-		dev_kfree_skb (lp->pending_tx_skb);
-		lp->pending_tx_skb = NULL;
-		lp->stats.tx_errors++;
-		lp->stats.tx_aborted_errors++;
-	}
 }
 
 /*
@@ -440,6 +442,7 @@
 {
 	struct smc_local *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
+	struct sk_buff *pending_skb;
 
 	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
 
@@ -447,7 +450,11 @@
 	spin_lock(&lp->lock);
 	SMC_SELECT_BANK(2);
 	SMC_SET_INT_MASK(0);
+	pending_skb = lp->pending_tx_skb;
+	lp->pending_tx_skb = NULL;
 	spin_unlock(&lp->lock);
+	if (pending_skb)
+		dev_kfree_skb(pending_skb);
 
 	/* and tell the card to stay away from that nasty outside world */
 	SMC_SELECT_BANK(0);
@@ -627,7 +634,12 @@
 	}
 
 	skb = lp->pending_tx_skb;
+	if (unlikely(!skb)) {
+		smc_special_unlock(&lp->lock);
+		return;
+	}
 	lp->pending_tx_skb = NULL;
+
 	packet_no = SMC_GET_AR();
 	if (unlikely(packet_no & AR_FAILED)) {
 		printk("%s: Memory allocation failed.\n", dev->name);
@@ -702,7 +714,6 @@
 	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
 
 	BUG_ON(lp->pending_tx_skb != NULL);
-	lp->pending_tx_skb = skb;
 
 	/*
 	 * The MMU wants the number of pages to be the number of 256 bytes
@@ -718,7 +729,6 @@
 	numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
 	if (unlikely(numPages > 7)) {
 		printk("%s: Far too big packet error.\n", dev->name);
-		lp->pending_tx_skb = NULL;
 		lp->stats.tx_errors++;
 		lp->stats.tx_dropped++;
 		dev_kfree_skb(skb);
@@ -745,6 +755,7 @@
 
 	smc_special_unlock(&lp->lock);
 
+	lp->pending_tx_skb = skb;
    	if (!poll_count) {
 		/* oh well, wait until the chip finds memory later */
 		netif_stop_queue(dev);
@@ -1062,7 +1073,7 @@
 	   above). linkwatch_event() also wants the netlink semaphore.
 	*/
 	while(lp->work_pending)
-		schedule();
+		yield();
 
 	bmcr = smc_phy_read(dev, phy, MII_BMCR);
 	smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
@@ -1606,14 +1617,8 @@
 
 	/* clear everything */
 	smc_shutdown(dev);
-
+	tasklet_kill(&lp->tx_task);
 	smc_phy_powerdown(dev);
-
-	if (lp->pending_tx_skb) {
-		dev_kfree_skb(lp->pending_tx_skb);
-		lp->pending_tx_skb = NULL;
-	}
-
 	return 0;
 }
 
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 6e5ade9..97712c3 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -455,8 +455,7 @@
 	writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
 	t = jiffies;
 	/* Hold soft reset bit for a while */
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout(HZ);
+	ssleep(1);
 	
 	writew(readw(streamer_mmio + BCTL) & ~BCTL_SOFTRESET,
 	       streamer_mmio + BCTL);
@@ -512,8 +511,7 @@
 	writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
 
 	while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/10);
+		msleep_interruptible(100);
 		if (jiffies - t > 40 * HZ) {
 			printk(KERN_ERR
 			       "IBM PCI tokenring card not responding\n");
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index cfc346e..08e0f80 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -242,6 +242,7 @@
  	{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X },	/* ALi 1563 integrated ethernet */
  	{ 0x10b9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X },	/* ALi 1563 integrated ethernet */
 	{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
+	{ 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */
 	{ } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -1756,11 +1757,19 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
-	if (dev && netif_running (dev) && netif_device_present (dev)) {
-		netif_device_detach (dev);
-		tulip_down (dev);
-		/* pci_power_off(pdev, -1); */
-	}
+	if (!dev)
+		return -EINVAL;
+
+	if (netif_running(dev))
+		tulip_down(dev);
+
+	netif_device_detach(dev);
+	free_irq(dev->irq, dev);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
 	return 0;
 }
 
@@ -1768,15 +1777,26 @@
 static int tulip_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	int retval;
 
-	if (dev && netif_running (dev) && !netif_device_present (dev)) {
-#if 1
-		pci_enable_device (pdev);
-#endif
-		/* pci_power_on(pdev); */
-		tulip_up (dev);
-		netif_device_attach (dev);
+	if (!dev)
+		return -EINVAL;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	pci_enable_device(pdev);
+
+	if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) {
+		printk (KERN_ERR "tulip: request_irq failed in resume\n");
+		return retval;
 	}
+
+	netif_device_attach(dev);
+
+	if (netif_running(dev))
+		tulip_up(dev);
+
 	return 0;
 }
 
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 6200cfc..be1c104 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1398,7 +1398,7 @@
 	while (rp->dirty_tx != rp->cur_tx) {
 		txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
 		if (debug > 6)
-			printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
+			printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n",
 			       entry, txstatus);
 		if (txstatus & DescOwn)
 			break;
@@ -1469,7 +1469,7 @@
 		int data_size = desc_status >> 16;
 
 		if (debug > 4)
-			printk(KERN_DEBUG " rhine_rx() status is %8.8x.\n",
+			printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n",
 			       desc_status);
 		if (--boguscnt < 0)
 			break;
@@ -1487,7 +1487,7 @@
 			} else if (desc_status & RxErr) {
 				/* There was a error. */
 				if (debug > 2)
-					printk(KERN_DEBUG " rhine_rx() Rx "
+					printk(KERN_DEBUG "rhine_rx() Rx "
 					       "error was %8.8x.\n",
 					       desc_status);
 				rp->stats.rx_errors++;
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 7575b79..7217d44 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -981,6 +981,7 @@
 	/* Wait for any previous command to complete */
 	while (mbval > NAK) {
 		spin_unlock_irqrestore(&card->card_lock, flags);
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1);
 		spin_lock_irqsave(&card->card_lock, flags);
 
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 1809688..c12648d 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -900,7 +900,7 @@
 	unsigned char __user *data;	// d-data
 } aironet_ioctl;
 
-static char *swversion = "2.1";
+static char swversion[] = "2.1";
 #endif /* CISCO_EXT */
 
 #define NUM_MODULES       2
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index b1078baa..aabcdc2 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -46,382 +46,9 @@
  * under either the MPL or the GPL.  */
 
 /*
- * v0.01 -> v0.02 - 21/3/2001 - Jean II
- *	o Allow to use regular ethX device name instead of dldwdX
- *	o Warning on IBSS with ESSID=any for firmware 6.06
- *	o Put proper range.throughput values (optimistic)
- *	o IWSPY support (IOCTL and stat gather in Rx path)
- *	o Allow setting frequency in Ad-Hoc mode
- *	o Disable WEP setting if !has_wep to work on old firmware
- *	o Fix txpower range
- *	o Start adding support for Samsung/Compaq firmware
- *
- * v0.02 -> v0.03 - 23/3/2001 - Jean II
- *	o Start adding Symbol support - need to check all that
- *	o Fix Prism2/Symbol WEP to accept 128 bits keys
- *	o Add Symbol WEP (add authentication type)
- *	o Add Prism2/Symbol rate
- *	o Add PM timeout (holdover duration)
- *	o Enable "iwconfig eth0 key off" and friends (toggle flags)
- *	o Enable "iwconfig eth0 power unicast/all" (toggle flags)
- *	o Try with an Intel card. It report firmware 1.01, behave like
- *	  an antiquated firmware, however on windows it says 2.00. Yuck !
- *	o Workaround firmware bug in allocate buffer (Intel 1.01)
- *	o Finish external renaming to orinoco...
- *	o Testing with various Wavelan firmwares
- *
- * v0.03 -> v0.04 - 30/3/2001 - Jean II
- *	o Update to Wireless 11 -> add retry limit/lifetime support
- *	o Tested with a D-Link DWL 650 card, fill in firmware support
- *	o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot)
- *	o Fixed the Prism2 WEP bugs that I introduced in v0.03 :-(
- *	  It works on D-Link *only* after a tcpdump. Weird...
- *	  And still doesn't work on Intel card. Grrrr...
- *	o Update the mode after a setport3
- *	o Add preamble setting for Symbol cards (not yet enabled)
- *	o Don't complain as much about Symbol cards...
- *
- * v0.04 -> v0.04b - 22/4/2001 - David Gibson
- *      o Removed the 'eth' parameter - always use ethXX as the
- *        interface name instead of dldwdXX.  The other was racy
- *        anyway.
- *	o Clean up RID definitions in hermes.h, other cleanups
- *
- * v0.04b -> v0.04c - 24/4/2001 - Jean II
- *	o Tim Hurley <timster AT seiki.bliztech.com> reported a D-Link card
- *	  with vendor 02 and firmware 0.08. Added in the capabilities...
- *	o Tested Lucent firmware 7.28, everything works...
- *
- * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt
- *	o Spin-off Pcmcia code. This file is renamed orinoco.c,
- *	  and orinoco_cs.c now contains only the Pcmcia specific stuff
- *	o Add Airport driver support on top of orinoco.c (see airport.c)
- *
- * v0.05 -> v0.05a - 4/5/2001 - Jean II
- *	o Revert to old Pcmcia code to fix breakage of Ben's changes...
- *
- * v0.05a -> v0.05b - 4/5/2001 - Jean II
- *	o add module parameter 'ignore_cis_vcc' for D-Link @ 5V
- *	o D-Link firmware doesn't support multicast. We just print a few
- *	  error messages, but otherwise everything works...
- *	o For David : set/getport3 works fine, just upgrade iwpriv...
- *
- * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt
- *	o Adapt airport.c to latest changes in orinoco.c
- *	o Remove deferred power enabling code
- *
- * v0.05c -> v0.05d - 5/5/2001 - Jean II
- *	o Workaround to SNAP decapsulate frame from Linksys AP
- *	  original patch from : Dong Liu <dliu AT research.bell-labs.com>
- *	  (note : the memcmp bug was mine - fixed)
- *	o Remove set_retry stuff, no firmware support it (bloat--).
- *
- * v0.05d -> v0.06 - 25/5/2001 - Jean II
- *		Original patch from "Hong Lin" <alin AT redhat.com>,
- *		"Ian Kinner" <ikinner AT redhat.com>
- *		and "David Smith" <dsmith AT redhat.com>
- *	o Init of priv->tx_rate_ctrl in firmware specific section.
- *	o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh !
- *	o Spectrum card always need cor_reset (for every reset)
- *	o Fix cor_reset to not lose bit 7 in the register
- *	o flush_stale_links to remove zombie Pcmcia instances
- *	o Ack previous hermes event before reset
- *		Me (with my little hands)
- *	o Allow orinoco.c to call cor_reset via priv->card_reset_handler
- *	o Add priv->need_card_reset to toggle this feature
- *	o Fix various buglets when setting WEP in Symbol firmware
- *	  Now, encryption is fully functional on Symbol cards. Youpi !
- *
- * v0.06 -> v0.06b - 25/5/2001 - Jean II
- *	o IBSS on Symbol use port_mode = 4. Please don't ask...
- *
- * v0.06b -> v0.06c - 29/5/2001 - Jean II
- *	o Show first spy address in /proc/net/wireless for IBSS mode as well
- *
- * v0.06c -> v0.06d - 6/7/2001 - David Gibson
- *      o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus'
- *        wishes to reduce the number of unnecessary messages.
- *	o Removed bogus message on CRC error.
- *	o Merged fixes for v0.08 Prism 2 firmware from William Waghorn
- *	  <willwaghorn AT yahoo.co.uk>
- *	o Slight cleanup/re-arrangement of firmware detection code.
- *
- * v0.06d -> v0.06e - 1/8/2001 - David Gibson
- *	o Removed some redundant global initializers (orinoco_cs.c).
- *	o Added some module metadata
- *
- * v0.06e -> v0.06f - 14/8/2001 - David Gibson
- *	o Wording fix to license
- *	o Added a 'use_alternate_encaps' module parameter for APs which need an
- *	  oui of 00:00:00.  We really need a better way of handling this, but
- *	  the module flag is better than nothing for now.
- *
- * v0.06f -> v0.07 - 20/8/2001 - David Gibson
- *	o Removed BAP error retries from hermes_bap_seek().  For Tx we now
- *	  let the upper layers handle the retry, we retry explicitly in the
- *	  Rx path, but don't make as much noise about it.
- *	o Firmware detection cleanups.
- *
- * v0.07 -> v0.07a - 1/10/3001 - Jean II
- *	o Add code to read Symbol firmware revision, inspired by latest code
- *	  in Spectrum24 by Lee John Keyser-Allen - Thanks Lee !
- *	o Thanks to Jared Valentine <hidden AT xmission.com> for "providing" me
- *	  a 3Com card with a recent firmware, fill out Symbol firmware
- *	  capabilities of latest rev (2.20), as well as older Symbol cards.
- *	o Disable Power Management in newer Symbol firmware, the API 
- *	  has changed (documentation needed).
- *
- * v0.07a -> v0.08 - 3/10/2001 - David Gibson
- *	o Fixed a possible buffer overrun found by the Stanford checker (in
- *	  dldwd_ioctl_setiwencode()).  Can only be called by root anyway, so not
- *	  a big problem.
- *	o Turned has_big_wep on for Intersil cards.  That's not true for all of
- *	  them but we should at least let the capable ones try.
- *	o Wait for BUSY to clear at the beginning of hermes_bap_seek().  I
- *	  realized that my assumption that the driver's serialization
- *	  would prevent the BAP being busy on entry was possibly false, because
- *	  things other than seeks may make the BAP busy.
- *	o Use "alternate" (oui 00:00:00) encapsulation by default.
- *	  Setting use_old_encaps will mimic the old behaviour, but I think we
- *	  will be able to eliminate this.
- *	o Don't try to make __initdata const (the version string).  This can't
- *	  work because of the way the __initdata sectioning works.
- *	o Added MODULE_LICENSE tags.
- *	o Support for PLX (transparent PCMCIA->PCI bridge) cards.
- *	o Changed to using the new type-fascist min/max.
- *
- * v0.08 -> v0.08a - 9/10/2001 - David Gibson
- *	o Inserted some missing acknowledgements/info into the Changelog.
- *	o Fixed some bugs in the normalization of signal level reporting.
- *	o Fixed bad bug in WEP key handling on Intersil and Symbol firmware,
- *	  which led to an instant crash on big-endian machines.
- *
- * v0.08a -> v0.08b - 20/11/2001 - David Gibson
- *	o Lots of cleanup and bugfixes in orinoco_plx.c
- *	o Cleanup to handling of Tx rate setting.
- *	o Removed support for old encapsulation method.
- *	o Removed old "dldwd" names.
- *	o Split RID constants into a new file hermes_rid.h
- *	o Renamed RID constants to match linux-wlan-ng and prism2.o
- *	o Bugfixes in hermes.c
- *	o Poke the PLX's INTCSR register, so it actually starts
- *	  generating interrupts.  These cards might actually work now.
- *	o Update to wireless extensions v12 (Jean II)
- *	o Support for tallies and inquire command (Jean II)
- *	o Airport updates for newer PPC kernels (BenH)
- *
- * v0.08b -> v0.09 - 21/12/2001 - David Gibson
- *	o Some new PCI IDs for PLX cards.
- *	o Removed broken attempt to do ALLMULTI reception.  Just use
- *	  promiscuous mode instead
- *	o Preliminary work for list-AP (Jean II)
- *	o Airport updates from (BenH)
- *	o Eliminated racy hw_ready stuff
- *	o Fixed generation of fake events in irq handler.  This should
- *	  finally kill the EIO problems (Jean II & dgibson)
- *	o Fixed breakage of bitrate set/get on Agere firmware (Jean II)
- *
- * v0.09 -> v0.09a - 2/1/2002 - David Gibson
- *	o Fixed stupid mistake in multicast list handling, triggering
- *	  a BUG()
- *
- * v0.09a -> v0.09b - 16/1/2002 - David Gibson
- *	o Fixed even stupider mistake in new interrupt handling, which
- *	  seriously broke things on big-endian machines.
- *	o Removed a bunch of redundant includes and exports.
- *	o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c
- *	o Don't attempt to do hardware level multicast reception on
- *	  Intersil firmware, just go promisc instead.
- *	o Typo fixed in hermes_issue_cmd()
- *	o Eliminated WIRELESS_SPY #ifdefs
- *	o Status code reported on Tx exceptions
- *	o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC
- *	  interrupts, which should fix the timeouts we're seeing.
- *
- * v0.09b -> v0.10 - 25 Feb 2002 - David Gibson
- *	o Removed nested structures used for header parsing, so the
- *	  driver should now work without hackery on ARM
- *	o Fix for WEP handling on Intersil (Hawk Newton)
- *	o Eliminated the /proc/hermes/ethXX/regs debugging file.  It
- *	  was never very useful.
- *	o Make Rx errors less noisy.
- *
- * v0.10 -> v0.11 - 5 Apr 2002 - David Gibson
- *	o Laid the groundwork in hermes.[ch] for devices which map
- *	  into PCI memory space rather than IO space.
- *	o Fixed bug in multicast handling (cleared multicast list when
- *	  leaving promiscuous mode).
- *	o Relegated Tx error messages to debug.
- *	o Cleaned up / corrected handling of allocation lengths.
- *	o Set OWNSSID in IBSS mode for WinXP interoperability (jimc).
- *	o Change to using alloc_etherdev() for structure allocations. 
- *	o Check for and drop undersized packets.
- *	o Fixed a race in stopping/waking the queue.  This should fix
- *	  the timeout problems (Pavel Roskin)
- *	o Reverted to netif_wake_queue() on the ALLOC event.
- *	o Fixes for recent Symbol firmwares which lack AP density
- *	  (Pavel Roskin).
- *
- * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
- *	o Handle different register spacing, necessary for Prism 2.5
- *	  PCI adaptors (Steve Hill).
- *	o Cleaned up initialization of card structures in orinoco_cs
- *	  and airport.  Removed card->priv field.
- *	o Make response structure optional for hermes_docmd_wait()
- *	  Pavel Roskin)
- *	o Added PCI id for Nortel emobility to orinoco_plx.c.
- *	o Cleanup to handling of Symbol's allocation bug. (Pavel Roskin)
- *	o Cleanups to firmware capability detection.
- *	o Arrange for orinoco_pci.c to override firmware detection.
- *	  We should be able to support the PCI Intersil cards now.
- *	o Cleanup handling of reset_cor and hard_reset (Pavel Roskin).
- *	o Remove erroneous use of USER_BAP in the TxExc handler (Jouni
- *	  Malinen).
- *	o Makefile changes for better integration into David Hinds
- *	  pcmcia-cs package.
- *
- * v0.11a -> v0.11b - 1 May 2002 - David Gibson
- *	o Better error reporting in orinoco_plx_init_one()
- *	o Fixed multiple bad kfree() bugs introduced by the
- *	  alloc_orinocodev() changes.
- *
- * v0.11b -> v0.12 - 19 Jun 2002 - David Gibson
- *	o Support changing the MAC address.
- *	o Correct display of Intersil firmware revision numbers.
- *	o Entirely revised locking scheme.  Should be both simpler and
- *	   better.
- *	o Merged some common code in orinoco_plx, orinoco_pci and
- *	  airport by creating orinoco_default_{open,stop,reset}()
- *	  which are used as the dev->open, dev->stop, priv->reset
- *	  callbacks if none are specified when alloc_orinocodev() is
- *	  called.
- *	o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt().
- *	  They didn't do anything.
- *
- * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
- *	o Some rearrangement of code.
- *	o Numerous fixups to locking and rest handling, particularly
- *	  for PCMCIA.
- *	o This allows open and stop net_device methods to be in
- *	  orinoco.c now, rather than in the init modules.
- *	o In orinoco_cs.c link->priv now points to the struct
- *	  net_device not to the struct orinoco_private.
- *	o Added a check for undersized SNAP frames, which could cause
- *	  crashes.
- *
- * v0.12a -> v0.12b - 11 Jul 2002 - David Gibson
- *	o Fix hw->num_init testing code, so num_init is actually
- *	  incremented.
- *	o Fix very stupid bug in orinoco_cs which broke compile with
- *	  CONFIG_SMP.
- *	o Squashed a warning.
- *
- * v0.12b -> v0.12c - 26 Jul 2002 - David Gibson
- *	o Change to C9X style designated initializers.
- *	o Add support for 3Com AirConnect PCI.
- *	o No longer ignore the hard_reset argument to
- *	  alloc_orinocodev().  Oops.
- *
- * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
- *	o Revert the broken 0.12* locking scheme and go to a new yet
- *	  simpler scheme.
- *	o Do firmware resets only in orinoco_init() and when waking
- *	  the card from hard sleep.
- *
- * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
- *	o Re-introduced full resets (via schedule_task()) on Tx
- *	  timeout.
- *
- * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
- *	o Minor cleanups to info frame handling.  Add basic support
- *	  for linkstatus info frames.
- *	o Include required kernel headers in orinoco.h, to avoid
- *	  compile problems.
- *
- * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
- *	o Implemented hard reset for Airport cards
- *	o Experimental suspend/resume implementation for orinoco_pci
- *	o Abolished /proc debugging support, replaced with a debugging
- *	  iwpriv.  Now it's ugly and simple instead of ugly and complex.
- *	o Bugfix in hermes.c if the firmware returned a record length
- *	  of 0, we could go clobbering memory.
- *	o Bugfix in orinoco_stop() - it used to fail if hw_unavailable
- *	  was set, which was usually true on PCMCIA hot removes.
- * 	o Track LINKSTATUS messages, silently drop Tx packets before
- * 	  we are connected (avoids confusing the firmware), and only
- * 	  give LINKSTATUS printk()s if the status has changed.
- *
- * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
- *	o Cleanup: use dev instead of priv in various places.
- *	o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
- *	  if we're in the middle of a (driver initiated) hard reset.
- *	o Bug fix: ETH_ZLEN is supposed to include the header
- *	  (Dionysus Blazakis & Manish Karir)
- *	o Convert to using workqueues instead of taskqueues (and
- *	  backwards compatibility macros for pre 2.5.41 kernels).
- *	o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
- *	  airport.c
- *	o New orinoco_tmd.c init module from Joerg Dorchain for
- *	  TMD7160 based PCI to PCMCIA bridges (similar to
- *	  orinoco_plx.c).
- *
- * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
- *	o Make hw_unavailable a counter, rather than just a flag, this
- *	  is necessary to avoid some races (such as a card being
- *	  removed in the middle of orinoco_reset().
- *	o Restore Release/RequestConfiguration in the PCMCIA event handler
- *	  when dealing with a driver initiated hard reset.  This is
- *	  necessary to prevent hangs due to a spurious interrupt while
- *	  the reset is in progress.
- *	o Clear the 802.11 header when transmitting, even though we
- *	  don't use it.  This fixes a long standing bug on some
- *	  firmwares, which seem to get confused if that isn't done.
- *	o Be less eager to de-encapsulate SNAP frames, only do so if
- *	  the OUI is 00:00:00 or 00:00:f8, leave others alone.  The old
- *	  behaviour broke CDP (Cisco Discovery Protocol).
- *	o Use dev instead of priv for free_irq() as well as
- *	  request_irq() (oops).
- *	o Attempt to reset rather than giving up if we get too many
- *	  IRQs.
- *	o Changed semantics of __orinoco_down() so it can be called
- *	  safely with hw_unavailable set.  It also now clears the
- *	  linkstatus (since we're going to have to reassociate).
- *
- * v0.13d -> v0.13e - 12 May 2003 - David Gibson
- *	o Support for post-2.5.68 return values from irq handler.
- *	o Fixed bug where underlength packets would be double counted
- *	  in the rx_dropped statistics.
- *	o Provided a module parameter to suppress linkstatus messages.
- *
- * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson
- *	o Replaced priv->connected logic with netif_carrier_on/off()
- *	  calls.
- *	o Remove has_ibss_any and never set the CREATEIBSS RID when
- *	  the ESSID is empty.  Too many firmwares break if we do.
- *	o 2.6 merges: Replace pdev->slot_name with pci_name(), remove
- *	  __devinitdata from PCI ID tables, use free_netdev().
- *	o Enabled shared-key authentication for Agere firmware (from
- *	  Robert J. Moore <Robert.J.Moore AT allanbank.com>
- *	o Move netif_wake_queue() (back) to the Tx completion from the
- *	  ALLOC event.  This seems to prevent/mitigate the rolling
- *	  error -110 problems at least on some Intersil firmwares.
- *	  Theoretically reduces performance, but I can't measure it.
- *	  Patch from Andrew Tridgell <tridge AT samba.org>
- *
- * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson
- *	o Correctly turn off shared-key authentication when requested
- *	  (bugfix from Robert J. Moore).
- *	o Correct airport sleep interfaces for current 2.6 kernels.
- *	o Add code for key change without disabling/enabling the MAC
- *	  port.  This is supposed to allow 802.1x to work sanely, but
- *	  doesn't seem to yet.
- *
  * TODO
- *	o New wireless extensions API (patch from Moustafa
- *	  Youssef, updated by Jim Carter and Pavel Roskin).
  *	o Handle de-encapsulation within network layer, provide 802.11
  *	  headers (patch from Thomas 'Dent' Mirlacher)
- *	o RF monitor mode support
  *	o Fix possible races in SPY handling.
  *	o Disconnect wireless extensions from fundamental configuration.
  *	o (maybe) Software WEP support (patch from Stano Meduna).
@@ -462,7 +89,10 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 #include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -496,6 +126,10 @@
 module_param(ignore_disconnect, int, 0644);
 MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
 
+static int force_monitor; /* = 0 */
+module_param(force_monitor, int, 0644);
+MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
+
 /********************************************************************/
 /* Compile time configuration and compatibility stuff               */
 /********************************************************************/
@@ -511,6 +145,10 @@
 /* Internal constants                                               */
 /********************************************************************/
 
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
+
 #define ORINOCO_MIN_MTU		256
 #define ORINOCO_MAX_MTU		(IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
 
@@ -537,6 +175,11 @@
 				 | HERMES_EV_WTERR | HERMES_EV_INFO \
 				 | HERMES_EV_INFDROP )
 
+#define MAX_RID_LEN 1024
+
+static const struct iw_handler_def orinoco_handler_def;
+static struct ethtool_ops orinoco_ethtool_ops;
+
 /********************************************************************/
 /* Data tables                                                      */
 /********************************************************************/
@@ -571,26 +214,45 @@
 /* Data types                                                       */
 /********************************************************************/
 
-struct header_struct {
-	/* 802.3 */
-	u8 dest[ETH_ALEN];
-	u8 src[ETH_ALEN];
-	u16 len;
-	/* 802.2 */
+/* Used in Event handling.
+ * We avoid nested structres as they break on ARM -- Moustafa */
+struct hermes_tx_descriptor_802_11 {
+	/* hermes_tx_descriptor */
+	u16 status;
+	u16 reserved1;
+	u16 reserved2;
+	u32 sw_support;
+	u8 retry_count;
+	u8 tx_rate;
+	u16 tx_control;
+
+	/* ieee802_11_hdr */
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+	u16 data_len;
+
+	/* ethhdr */
+	unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
+	unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
+	unsigned short  h_proto;                /* packet type ID field */
+
+	/* p8022_hdr */
 	u8 dsap;
 	u8 ssap;
 	u8 ctrl;
-	/* SNAP */
 	u8 oui[3];
+
 	u16 ethertype;
 } __attribute__ ((packed));
 
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-
-#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
-
+/* Rx frame header except compatibility 802.3 header */
 struct hermes_rx_descriptor {
+	/* Control */
 	u16 status;
 	u32 time;
 	u8 silence;
@@ -598,13 +260,24 @@
 	u8 rate;
 	u8 rxflow;
 	u32 reserved;
+
+	/* 802.11 header */
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+
+	/* Data length */
+	u16 data_len;
 } __attribute__ ((packed));
 
 /********************************************************************/
 /* Function prototypes                                              */
 /********************************************************************/
 
-static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int __orinoco_program_rids(struct net_device *dev);
 static void __orinoco_set_multicast_list(struct net_device *dev);
 
@@ -628,6 +301,10 @@
 			priv->createibss = 1;
 		}
 		break;
+	case IW_MODE_MONITOR:
+		priv->port_type = 3;
+		priv->createibss = 0;
+		break;
 	default:
 		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
 		       priv->ndev->name);
@@ -814,7 +491,7 @@
 		return 1;
 	}
 
-	if (! netif_carrier_ok(dev)) {
+	if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
 		/* Oops, the firmware hasn't established a connection,
                    silently drop the packet (this seems to be the
                    safest approach). */
@@ -951,26 +628,55 @@
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
-	struct hermes_tx_descriptor desc;
+	struct hermes_tx_descriptor_802_11 hdr;
 	int err = 0;
 
 	if (fid == DUMMY_FID)
 		return; /* Nothing's really happened */
 
-	err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
+	/* Read the frame header */
+	err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
+			       sizeof(struct hermes_tx_descriptor) +
+			       sizeof(struct ieee80211_hdr),
+			       fid, 0);
+
+	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+	stats->tx_errors++;
+
 	if (err) {
 		printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
 		       "(FID=%04X error %d)\n",
 		       dev->name, fid, err);
-	} else {
-		DEBUG(1, "%s: Tx error, status %d\n",
-		      dev->name, le16_to_cpu(desc.status));
+		return;
 	}
 	
-	stats->tx_errors++;
+	DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
+	      err, fid);
+    
+	/* We produce a TXDROP event only for retry or lifetime
+	 * exceeded, because that's the only status that really mean
+	 * that this particular node went away.
+	 * Other errors means that *we* screwed up. - Jean II */
+	hdr.status = le16_to_cpu(hdr.status);
+	if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
+		union iwreq_data	wrqu;
+
+		/* Copy 802.11 dest address.
+		 * We use the 802.11 header because the frame may
+		 * not be 802.3 or may be mangled...
+		 * In Ad-Hoc mode, it will be the node address.
+		 * In managed mode, it will be most likely the AP addr
+		 * User space will figure out how to convert it to
+		 * whatever it needs (IP address or else).
+		 * - Jean II */
+		memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
+		wrqu.addr.sa_family = ARPHRD_ETHER;
+
+		/* Send event to user space */
+		wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+	}
 
 	netif_wake_queue(dev);
-	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
 static void orinoco_tx_timeout(struct net_device *dev)
@@ -1047,18 +753,127 @@
 	}
 }
 
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ *	dev		network device
+ *	rxfid		received FID
+ *	desc		rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+			       struct hermes_rx_descriptor *desc)
+{
+	u32 hdrlen = 30;	/* return full header by default */
+	u32 datalen = 0;
+	u16 fc;
+	int err;
+	int len;
+	struct sk_buff *skb;
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	hermes_t *hw = &priv->hw;
+
+	len = le16_to_cpu(desc->data_len);
+
+	/* Determine the size of the header and the data */
+	fc = le16_to_cpu(desc->frame_ctl);
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_DATA:
+		if ((fc & IEEE80211_FCTL_TODS)
+		    && (fc & IEEE80211_FCTL_FROMDS))
+			hdrlen = 30;
+		else
+			hdrlen = 24;
+		datalen = len;
+		break;
+	case IEEE80211_FTYPE_MGMT:
+		hdrlen = 24;
+		datalen = len;
+		break;
+	case IEEE80211_FTYPE_CTL:
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_PSPOLL:
+		case IEEE80211_STYPE_RTS:
+		case IEEE80211_STYPE_CFEND:
+		case IEEE80211_STYPE_CFENDACK:
+			hdrlen = 16;
+			break;
+		case IEEE80211_STYPE_CTS:
+		case IEEE80211_STYPE_ACK:
+			hdrlen = 10;
+			break;
+		}
+		break;
+	default:
+		/* Unknown frame type */
+		break;
+	}
+
+	/* sanity check the length */
+	if (datalen > IEEE80211_DATA_LEN + 12) {
+		printk(KERN_DEBUG "%s: oversized monitor frame, "
+		       "data length = %d\n", dev->name, datalen);
+		err = -EIO;
+		stats->rx_length_errors++;
+		goto update_stats;
+	}
+
+	skb = dev_alloc_skb(hdrlen + datalen);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+		       dev->name);
+		err = -ENOMEM;
+		goto drop;
+	}
+
+	/* Copy the 802.11 header to the skb */
+	memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+	skb->mac.raw = skb->data;
+
+	/* If any, copy the data from the card to the skb */
+	if (datalen > 0) {
+		err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+				       ALIGN(datalen, 2), rxfid,
+				       HERMES_802_2_OFFSET);
+		if (err) {
+			printk(KERN_ERR "%s: error %d reading monitor frame\n",
+			       dev->name, err);
+			goto drop;
+		}
+	}
+
+	skb->dev = dev;
+	skb->ip_summed = CHECKSUM_NONE;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = __constant_htons(ETH_P_802_2);
+	
+	dev->last_rx = jiffies;
+	stats->rx_packets++;
+	stats->rx_bytes += skb->len;
+
+	netif_rx(skb);
+	return;
+
+ drop:
+	dev_kfree_skb_irq(skb);
+ update_stats:
+	stats->rx_errors++;
+	stats->rx_dropped++;
+}
+
 static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	struct iw_statistics *wstats = &priv->wstats;
 	struct sk_buff *skb = NULL;
-	u16 rxfid, status;
-	int length, data_len, data_off;
-	char *p;
+	u16 rxfid, status, fc;
+	int length;
 	struct hermes_rx_descriptor desc;
-	struct header_struct hdr;
-	struct ethhdr *eh;
+	struct ethhdr *hdr;
 	int err;
 
 	rxfid = hermes_read_regn(hw, RXFID);
@@ -1068,53 +883,46 @@
 	if (err) {
 		printk(KERN_ERR "%s: error %d reading Rx descriptor. "
 		       "Frame dropped.\n", dev->name, err);
-		stats->rx_errors++;
-		goto drop;
+		goto update_stats;
 	}
 
 	status = le16_to_cpu(desc.status);
 
-	if (status & HERMES_RXSTAT_ERR) {
-		if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
-			wstats->discard.code++;
-			DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
-			       dev->name);
-		} else {
-			stats->rx_crc_errors++;
-			DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
-		}
-		stats->rx_errors++;
-		goto drop;
+	if (status & HERMES_RXSTAT_BADCRC) {
+		DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+		      dev->name);
+		stats->rx_crc_errors++;
+		goto update_stats;
 	}
 
-	/* For now we ignore the 802.11 header completely, assuming
-           that the card's firmware has handled anything vital */
-
-	err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
-			       rxfid, HERMES_802_3_OFFSET);
-	if (err) {
-		printk(KERN_ERR "%s: error %d reading frame header. "
-		       "Frame dropped.\n", dev->name, err);
-		stats->rx_errors++;
-		goto drop;
+	/* Handle frames in monitor mode */
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		orinoco_rx_monitor(dev, rxfid, &desc);
+		return;
 	}
 
-	length = ntohs(hdr.len);
-	
+	if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+		DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+		      dev->name);
+		wstats->discard.code++;
+		goto update_stats;
+	}
+
+	length = le16_to_cpu(desc.data_len);
+	fc = le16_to_cpu(desc.frame_ctl);
+
 	/* Sanity checks */
 	if (length < 3) { /* No for even an 802.2 LLC header */
 		/* At least on Symbol firmware with PCF we get quite a
                    lot of these legitimately - Poll frames with no
                    data. */
-		stats->rx_dropped++;
-		goto drop;
+		return;
 	}
 	if (length > IEEE802_11_DATA_LEN) {
 		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
 		       dev->name, length);
 		stats->rx_length_errors++;
-		stats->rx_errors++;
-		goto drop;
+		goto update_stats;
 	}
 
 	/* We need space for the packet data itself, plus an ethernet
@@ -1126,60 +934,53 @@
 	if (!skb) {
 		printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
 		       dev->name);
-		goto drop;
+		goto update_stats;
 	}
 
-	skb_reserve(skb, 2); /* This way the IP header is aligned */
+	/* We'll prepend the header, so reserve space for it.  The worst
+	   case is no decapsulation, when 802.3 header is prepended and
+	   nothing is removed.  2 is for aligning the IP header.  */
+	skb_reserve(skb, ETH_HLEN + 2);
+
+	err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+			       ALIGN(length, 2), rxfid,
+			       HERMES_802_2_OFFSET);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading frame. "
+		       "Frame dropped.\n", dev->name, err);
+		goto drop;
+	}
 
 	/* Handle decapsulation
 	 * In most cases, the firmware tell us about SNAP frames.
 	 * For some reason, the SNAP frames sent by LinkSys APs
 	 * are not properly recognised by most firmwares.
 	 * So, check ourselves */
-	if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
-	    ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-	    is_ethersnap(&hdr)) {
+	if (length >= ENCAPS_OVERHEAD &&
+	    (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+	     ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+	     is_ethersnap(skb->data))) {
 		/* These indicate a SNAP within 802.2 LLC within
 		   802.11 frame which we'll need to de-encapsulate to
 		   the original EthernetII frame. */
-
-		if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
-			stats->rx_length_errors++;
-			goto drop;
-		}
-
-		/* Remove SNAP header, reconstruct EthernetII frame */
-		data_len = length - ENCAPS_OVERHEAD;
-		data_off = HERMES_802_3_OFFSET + sizeof(hdr);
-
-		eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
-
-		memcpy(eh, &hdr, 2 * ETH_ALEN);
-		eh->h_proto = hdr.ethertype;
+		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
 	} else {
-		/* All other cases indicate a genuine 802.3 frame.  No
-		   decapsulation needed.  We just throw the whole
-		   thing in, and hope the protocol layer can deal with
-		   it as 802.3 */
-		data_len = length;
-		data_off = HERMES_802_3_OFFSET;
-		/* FIXME: we re-read from the card data we already read here */
+		/* 802.3 frame - prepend 802.3 header as is */
+		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+		hdr->h_proto = htons(length);
 	}
-
-	p = skb_put(skb, data_len);
-	err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2),
-			       rxfid, data_off);
-	if (err) {
-		printk(KERN_ERR "%s: error %d reading frame. "
-		       "Frame dropped.\n", dev->name, err);
-		stats->rx_errors++;
-		goto drop;
-	}
+	memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
+	if (fc & IEEE80211_FCTL_FROMDS)
+		memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
+	else
+		memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
 
 	dev->last_rx = jiffies;
 	skb->dev = dev;
 	skb->protocol = eth_type_trans(skb, dev);
 	skb->ip_summed = CHECKSUM_NONE;
+	if (fc & IEEE80211_FCTL_TODS)
+		skb->pkt_type = PACKET_OTHERHOST;
 	
 	/* Process the wireless stats if needed */
 	orinoco_stat_gather(dev, skb, &desc);
@@ -1192,11 +993,10 @@
 	return;
 
  drop:	
+	dev_kfree_skb_irq(skb);
+ update_stats:
+	stats->rx_errors++;
 	stats->rx_dropped++;
-
-	if (skb)
-		dev_kfree_skb_irq(skb);
-	return;
 }
 
 /********************************************************************/
@@ -1240,6 +1040,99 @@
 	       dev->name, s, status);
 }
 
+/* Search scan results for requested BSSID, join it if found */
+static void orinoco_join_ap(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	int err;
+	unsigned long flags;
+	struct join_req {
+		u8 bssid[ETH_ALEN];
+		u16 channel;
+	} __attribute__ ((packed)) req;
+	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
+	struct prism2_scan_apinfo *atom;
+	int offset = 4;
+	u8 *buf;
+	u16 len;
+
+	/* Allocate buffer for scan results */
+	buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
+	if (! buf)
+		return;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		goto out;
+
+	/* Sanity checks in case user changed something in the meantime */
+	if (! priv->bssid_fixed)
+		goto out;
+
+	if (strlen(priv->desired_essid) == 0)
+		goto out;
+
+	/* Read scan results from the firmware */
+	err = hermes_read_ltv(hw, USER_BAP,
+			      HERMES_RID_SCANRESULTSTABLE,
+			      MAX_SCAN_LEN, &len, buf);
+	if (err) {
+		printk(KERN_ERR "%s: Cannot read scan results\n",
+		       dev->name);
+		goto out;
+	}
+
+	len = HERMES_RECLEN_TO_BYTES(len);
+
+	/* Go through the scan results looking for the channel of the AP
+	 * we were requested to join */
+	for (; offset + atom_len <= len; offset += atom_len) {
+		atom = (struct prism2_scan_apinfo *) (buf + offset);
+		if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
+			goto found;
+	}
+
+	DEBUG(1, "%s: Requested AP not found in scan results\n",
+	      dev->name);
+	goto out;
+
+ found:
+	memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
+	req.channel = atom->channel;	/* both are little-endian */
+	err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
+				  &req);
+	if (err)
+		printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
+
+ out:
+	kfree(buf);
+	orinoco_unlock(priv, &flags);
+}
+
+/* Send new BSSID to userspace */
+static void orinoco_send_wevents(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	union iwreq_data wrqu;
+	int err;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return;
+
+	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+	if (err != 0)
+		return;
+
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+	/* Send event to user space */
+	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+	orinoco_unlock(priv, &flags);
+}
+
 static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
@@ -1307,6 +1200,9 @@
 		u16 newstatus;
 		int connected;
 
+		if (priv->iw_mode == IW_MODE_MONITOR)
+			break;
+
 		if (len != sizeof(linkstatus)) {
 			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
 			       dev->name, len);
@@ -1319,6 +1215,15 @@
 			break;
 		newstatus = le16_to_cpu(linkstatus.linkstatus);
 
+		/* Symbol firmware uses "out of range" to signal that
+		 * the hostscan frame can be requested.  */
+		if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
+		    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
+		    priv->has_hostscan && priv->scan_inprogress) {
+			hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
+			break;
+		}
+
 		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
 			|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
 			|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
@@ -1328,12 +1233,89 @@
 		else if (!ignore_disconnect)
 			netif_carrier_off(dev);
 
-		if (newstatus != priv->last_linkstatus)
+		if (newstatus != priv->last_linkstatus) {
+			priv->last_linkstatus = newstatus;
 			print_linkstatus(dev, newstatus);
-
-		priv->last_linkstatus = newstatus;
+			/* The info frame contains only one word which is the
+			 * status (see hermes.h). The status is pretty boring
+			 * in itself, that's why we export the new BSSID...
+			 * Jean II */
+			schedule_work(&priv->wevent_work);
+		}
 	}
 	break;
+	case HERMES_INQ_SCAN:
+		if (!priv->scan_inprogress && priv->bssid_fixed &&
+		    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+			schedule_work(&priv->join_work);
+			break;
+		}
+		/* fall through */
+	case HERMES_INQ_HOSTSCAN:
+	case HERMES_INQ_HOSTSCAN_SYMBOL: {
+		/* Result of a scanning. Contains information about
+		 * cells in the vicinity - Jean II */
+		union iwreq_data	wrqu;
+		unsigned char *buf;
+
+		/* Sanity check */
+		if (len > 4096) {
+			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
+			       dev->name, len);
+			break;
+		}
+
+		/* We are a strict producer. If the previous scan results
+		 * have not been consumed, we just have to drop this
+		 * frame. We can't remove the previous results ourselves,
+		 * that would be *very* racy... Jean II */
+		if (priv->scan_result != NULL) {
+			printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
+			break;
+		}
+
+		/* Allocate buffer for results */
+		buf = kmalloc(len, GFP_ATOMIC);
+		if (buf == NULL)
+			/* No memory, so can't printk()... */
+			break;
+
+		/* Read scan data */
+		err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
+				       infofid, sizeof(info));
+		if (err)
+			break;
+
+#ifdef ORINOCO_DEBUG
+		{
+			int	i;
+			printk(KERN_DEBUG "Scan result [%02X", buf[0]);
+			for(i = 1; i < (len * 2); i++)
+				printk(":%02X", buf[i]);
+			printk("]\n");
+		}
+#endif	/* ORINOCO_DEBUG */
+
+		/* Allow the clients to access the results */
+		priv->scan_len = len;
+		priv->scan_result = buf;
+
+		/* Send an empty event to user space.
+		 * We don't send the received data on the event because
+		 * it would require us to do complex transcoding, and
+		 * we want to minimise the work done in the irq handler
+		 * Use a request to extract the data - Jean II */
+		wrqu.data.length = 0;
+		wrqu.data.flags = 0;
+		wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+	}
+	break;
+	case HERMES_INQ_SEC_STAT_AGERE:
+		/* Security status (Agere specific) */
+		/* Ignore this frame for now */
+		if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+			break;
+		/* fall through */
 	default:
 		printk(KERN_DEBUG "%s: Unknown information frame received: "
 		       "type 0x%04x, length %d\n", dev->name, type, len);
@@ -1470,6 +1452,36 @@
 	return err;
 }
 
+/* Set fixed AP address */
+static int __orinoco_hw_set_wap(struct orinoco_private *priv)
+{
+	int roaming_flag;
+	int err = 0;
+	hermes_t *hw = &priv->hw;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		/* not supported */
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		if (priv->bssid_fixed)
+			roaming_flag = 2;
+		else
+			roaming_flag = 1;
+
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFROAMINGMODE,
+					   roaming_flag);
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		err = HERMES_WRITE_RECORD(hw, USER_BAP,
+					  HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
+					  &priv->desired_bssid);
+		break;
+	}
+	return err;
+}
+
 /* Change the WEP keys and/or the current keys.  Can be called
  * either from __orinoco_hw_setup_wep() or directly from
  * orinoco_ioctl_setiwencode().  In the later case the association
@@ -1655,6 +1667,13 @@
 		}
 	}
 
+	/* Set the desired BSSID */
+	err = __orinoco_hw_set_wap(priv);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting AP address\n",
+		       dev->name, err);
+		return err;
+	}
 	/* Set the desired ESSID */
 	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
 	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
@@ -1793,6 +1812,20 @@
 		}
 	}
 
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		/* Enable monitor mode */
+		dev->type = ARPHRD_IEEE80211;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST | 
+					    HERMES_TEST_MONITOR, 0, NULL);
+	} else {
+		/* Disable monitor mode */
+		dev->type = ARPHRD_ETHER;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+					    HERMES_TEST_STOP, 0, NULL);
+	}
+	if (err)
+		return err;
+
 	/* Set promiscuity / multicast*/
 	priv->promiscuous = 0;
 	priv->mc_count = 0;
@@ -1869,55 +1902,6 @@
 		dev->flags &= ~IFF_PROMISC;
 }
 
-static int orinoco_reconfigure(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct hermes *hw = &priv->hw;
-	unsigned long flags;
-	int err = 0;
-
-	if (priv->broken_disableport) {
-		schedule_work(&priv->reset_work);
-		return 0;
-	}
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-		
-	err = hermes_disable_port(hw, 0);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
-		       dev->name);
-		priv->broken_disableport = 1;
-		goto out;
-	}
-
-	err = __orinoco_program_rids(dev);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to reconfigure card\n",
-		       dev->name);
-		goto out;
-	}
-
-	err = hermes_enable_port(hw, 0);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
-		       dev->name);
-		goto out;
-	}
-
- out:
-	if (err) {
-		printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
-		schedule_work(&priv->reset_work);
-		err = 0;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return err;
-
-}
-
 /* This must be called from user context, without locks held - use
  * schedule_work() */
 static void orinoco_reset(struct net_device *dev)
@@ -1946,6 +1930,11 @@
 
 	orinoco_unlock(priv, &flags);
 
+ 	/* Scanning support: Cleanup of driver struct */
+	kfree(priv->scan_result);
+	priv->scan_result = NULL;
+	priv->scan_inprogress = 0;
+
 	if (priv->hard_reset) {
 		err = (*priv->hard_reset)(priv);
 		if (err) {
@@ -2184,6 +2173,8 @@
 		priv->has_mwo = (firmver >= 0x60000);
 		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
 		priv->ibss_port = 1;
+		priv->has_hostscan = (firmver >= 0x8000a);
+		priv->broken_monitor = (firmver >= 0x80000);
 
 		/* Tested with Agere firmware :
 		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2229,6 +2220,8 @@
 		priv->ibss_port = 4;
  		priv->broken_disableport = (firmver == 0x25013) ||
  					   (firmver >= 0x30000 && firmver <= 0x31000);
+		priv->has_hostscan = (firmver >= 0x31001) ||
+				     (firmver >= 0x29057 && firmver < 0x30000);
 		/* Tested with Intel firmware : 0x20015 => Jean II */
 		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
 		break;
@@ -2248,6 +2241,7 @@
 		priv->has_ibss = (firmver >= 0x000700); /* FIXME */
 		priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
 		priv->has_pm = (firmver >= 0x000700);
+		priv->has_hostscan = (firmver >= 0x010301);
 
 		if (firmver >= 0x000800)
 			priv->ibss_port = 0;
@@ -2456,8 +2450,9 @@
 	dev->tx_timeout = orinoco_tx_timeout;
 	dev->watchdog_timeo = HZ; /* 1 second timeout */
 	dev->get_stats = orinoco_get_stats;
+	dev->ethtool_ops = &orinoco_ethtool_ops;
 	dev->get_wireless_stats = orinoco_get_wireless_stats;
-	dev->do_ioctl = orinoco_ioctl;
+	dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
 	dev->change_mtu = orinoco_change_mtu;
 	dev->set_multicast_list = orinoco_set_multicast_list;
 	/* we use the default eth_mac_addr for setting the MAC addr */
@@ -2473,6 +2468,8 @@
 				   * before anything else touches the
 				   * hardware */
 	INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+	INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev);
+	INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);
 
 	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
@@ -2483,6 +2480,9 @@
 
 void free_orinocodev(struct net_device *dev)
 {
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	kfree(priv->scan_result);
 	free_netdev(dev);
 }
 
@@ -2490,24 +2490,6 @@
 /* Wireless extensions                                              */
 /********************************************************************/
 
-static int orinoco_hw_get_bssid(struct orinoco_private *priv,
-				char buf[ETH_ALEN])
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-			      ETH_ALEN, NULL, buf);
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
 static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
 				char buf[IW_ESSID_MAX_SIZE+1])
 {
@@ -2633,140 +2615,271 @@
 	return 0;
 }
 
-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+static int orinoco_ioctl_getname(struct net_device *dev,
+				 struct iw_request_info *info,
+				 char *name,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
-	int mode;
-	struct iw_range range;
 	int numrates;
-	int i, k;
+	int err;
+
+	err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
+
+	if (!err && (numrates > 2))
+		strcpy(name, "IEEE 802.11b");
+	else
+		strcpy(name, "IEEE 802.11-DS");
+
+	return 0;
+}
+
+static int orinoco_ioctl_setwap(struct net_device *dev,
+				struct iw_request_info *info,
+				struct sockaddr *ap_addr,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = -EINPROGRESS;		/* Call commit handler */
 	unsigned long flags;
-
-	TRACE_ENTER(dev->name);
-
-	if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range)))
-		return -EFAULT;
-
-	rrq->length = sizeof(range);
+	static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	mode = priv->iw_mode;
+	/* Enable automatic roaming - no sanity checks are needed */
+	if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
+	    memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+		priv->bssid_fixed = 0;
+		memset(priv->desired_bssid, 0, ETH_ALEN);
+
+		/* "off" means keep existing connection */
+		if (ap_addr->sa_data[0] == 0) {
+			__orinoco_hw_set_wap(priv);
+			err = 0;
+		}
+		goto out;
+	}
+
+	if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
+		printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
+		       "support manual roaming\n",
+		       dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (priv->iw_mode != IW_MODE_INFRA) {
+		printk(KERN_WARNING "%s: Manual roaming supported only in "
+		       "managed mode\n", dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Intersil firmware hangs without Desired ESSID */
+	if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
+	    strlen(priv->desired_essid) == 0) {
+		printk(KERN_WARNING "%s: Desired ESSID must be set for "
+		       "manual roaming\n", dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Finally, enable manual roaming */
+	priv->bssid_fixed = 1;
+	memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
+
+ out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+				struct iw_request_info *info,
+				struct sockaddr *ap_addr,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	ap_addr->sa_family = ARPHRD_ETHER;
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+			      ETH_ALEN, NULL, ap_addr->sa_data);
+
 	orinoco_unlock(priv, &flags);
 
-	memset(&range, 0, sizeof(range));
+	return err;
+}
 
-	/* Much of this shamelessly taken from wvlan_cs.c. No idea
-	 * what it all means -dgibson */
-	range.we_version_compiled = WIRELESS_EXT;
-	range.we_version_source = 11;
+static int orinoco_ioctl_setmode(struct net_device *dev,
+				 struct iw_request_info *info,
+				 u32 *mode,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = -EINPROGRESS;		/* Call commit handler */
+	unsigned long flags;
 
-	range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+	if (priv->iw_mode == *mode)
+		return 0;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (*mode) {
+	case IW_MODE_ADHOC:
+		if (!priv->has_ibss && !priv->has_port3)
+			err = -EOPNOTSUPP;
+		break;
+
+	case IW_MODE_INFRA:
+		break;
+
+	case IW_MODE_MONITOR:
+		if (priv->broken_monitor && !force_monitor) {
+			printk(KERN_WARNING "%s: Monitor mode support is "
+			       "buggy in this firmware, not enabling\n",
+			       dev->name);
+			err = -EOPNOTSUPP;
+		}
+		break;
+
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	if (err == -EINPROGRESS) {
+		priv->iw_mode = *mode;
+		set_port_type(priv);
+	}
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_getmode(struct net_device *dev,
+				 struct iw_request_info *info,
+				 u32 *mode,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	*mode = priv->iw_mode;
+	return 0;
+}
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_point *rrq,
+				    char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+	struct iw_range *range = (struct iw_range *) extra;
+	int numrates;
+	int i, k;
+
+	TRACE_ENTER(dev->name);
+
+	rrq->length = sizeof(struct iw_range);
+	memset(range, 0, sizeof(struct iw_range));
+
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = 14;
 
 	/* Set available channels/frequencies */
-	range.num_channels = NUM_CHANNELS;
+	range->num_channels = NUM_CHANNELS;
 	k = 0;
 	for (i = 0; i < NUM_CHANNELS; i++) {
 		if (priv->channel_mask & (1 << i)) {
-			range.freq[k].i = i + 1;
-			range.freq[k].m = channel_frequency[i] * 100000;
-			range.freq[k].e = 1;
+			range->freq[k].i = i + 1;
+			range->freq[k].m = channel_frequency[i] * 100000;
+			range->freq[k].e = 1;
 			k++;
 		}
 		
 		if (k >= IW_MAX_FREQUENCIES)
 			break;
 	}
-	range.num_frequency = k;
+	range->num_frequency = k;
+	range->sensitivity = 3;
 
-	range.sensitivity = 3;
+	if (priv->has_wep) {
+		range->max_encoding_tokens = ORINOCO_MAX_KEYS;
+		range->encoding_size[0] = SMALL_KEY_SIZE;
+		range->num_encoding_sizes = 1;
 
-	if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
+		if (priv->has_big_wep) {
+			range->encoding_size[1] = LARGE_KEY_SIZE;
+			range->num_encoding_sizes = 2;
+		}
+	}
+
+	if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
 		/* Quality stats meaningless in ad-hoc mode */
-		range.max_qual.qual = 0;
-		range.max_qual.level = 0;
-		range.max_qual.noise = 0;
-		range.avg_qual.qual = 0;
-		range.avg_qual.level = 0;
-		range.avg_qual.noise = 0;
 	} else {
-		range.max_qual.qual = 0x8b - 0x2f;
-		range.max_qual.level = 0x2f - 0x95 - 1;
-		range.max_qual.noise = 0x2f - 0x95 - 1;
+		range->max_qual.qual = 0x8b - 0x2f;
+		range->max_qual.level = 0x2f - 0x95 - 1;
+		range->max_qual.noise = 0x2f - 0x95 - 1;
 		/* Need to get better values */
-		range.avg_qual.qual = 0x24;
-		range.avg_qual.level = 0xC2;
-		range.avg_qual.noise = 0x9E;
+		range->avg_qual.qual = 0x24;
+		range->avg_qual.level = 0xC2;
+		range->avg_qual.noise = 0x9E;
 	}
 
 	err = orinoco_hw_get_bitratelist(priv, &numrates,
-					 range.bitrate, IW_MAX_BITRATES);
+					 range->bitrate, IW_MAX_BITRATES);
 	if (err)
 		return err;
-	range.num_bitrates = numrates;
-	
+	range->num_bitrates = numrates;
+
 	/* Set an indication of the max TCP throughput in bit/s that we can
 	 * expect using this interface. May be use for QoS stuff...
 	 * Jean II */
-	if(numrates > 2)
-		range.throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
+	if (numrates > 2)
+		range->throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
 	else
-		range.throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
+		range->throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
 
-	range.min_rts = 0;
-	range.max_rts = 2347;
-	range.min_frag = 256;
-	range.max_frag = 2346;
+	range->min_rts = 0;
+	range->max_rts = 2347;
+	range->min_frag = 256;
+	range->max_frag = 2346;
 
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-	if (priv->has_wep) {
-		range.max_encoding_tokens = ORINOCO_MAX_KEYS;
+	range->min_pmp = 0;
+	range->max_pmp = 65535000;
+	range->min_pmt = 0;
+	range->max_pmt = 65535 * 1000;	/* ??? */
+	range->pmp_flags = IW_POWER_PERIOD;
+	range->pmt_flags = IW_POWER_TIMEOUT;
+	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
 
-		range.encoding_size[0] = SMALL_KEY_SIZE;
-		range.num_encoding_sizes = 1;
-
-		if (priv->has_big_wep) {
-			range.encoding_size[1] = LARGE_KEY_SIZE;
-			range.num_encoding_sizes = 2;
-		}
-	} else {
-		range.num_encoding_sizes = 0;
-		range.max_encoding_tokens = 0;
-	}
-	orinoco_unlock(priv, &flags);
-		
-	range.min_pmp = 0;
-	range.max_pmp = 65535000;
-	range.min_pmt = 0;
-	range.max_pmt = 65535 * 1000;	/* ??? */
-	range.pmp_flags = IW_POWER_PERIOD;
-	range.pmt_flags = IW_POWER_TIMEOUT;
-	range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
-	range.num_txpower = 1;
-	range.txpower[0] = 15; /* 15dBm */
-	range.txpower_capa = IW_TXPOW_DBM;
-
-	range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-	range.retry_flags = IW_RETRY_LIMIT;
-	range.r_time_flags = IW_RETRY_LIFETIME;
-	range.min_retry = 0;
-	range.max_retry = 65535;	/* ??? */
-	range.min_r_time = 0;
-	range.max_r_time = 65535 * 1000;	/* ??? */
-
-	if (copy_to_user(rrq->pointer, &range, sizeof(range)))
-		return -EFAULT;
+	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->r_time_flags = IW_RETRY_LIFETIME;
+	range->min_retry = 0;
+	range->max_retry = 65535;	/* ??? */
+	range->min_r_time = 0;
+	range->max_r_time = 65535 * 1000;	/* ??? */
 
 	TRACE_EXIT(dev->name);
 
 	return 0;
 }
 
-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     struct iw_point *erq,
+				     char *keybuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
@@ -2774,8 +2887,7 @@
 	int enable = priv->wep_on;
 	int restricted = priv->wep_restrict;
 	u16 xlen = 0;
-	int err = 0;
-	char keybuf[ORINOCO_MAX_KEY_SIZE];
+	int err = -EINPROGRESS;		/* Call commit handler */
 	unsigned long flags;
 
 	if (! priv->has_wep)
@@ -2788,9 +2900,6 @@
 
 		if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
 			return -E2BIG;
-		
-		if (copy_from_user(keybuf, erq->pointer, erq->length))
-			return -EFAULT;
 	}
 
 	if (orinoco_lock(priv, &flags) != 0)
@@ -2864,12 +2973,14 @@
 	return err;
 }
 
-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     struct iw_point *erq,
+				     char *keybuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	u16 xlen = 0;
-	char keybuf[ORINOCO_MAX_KEY_SIZE];
 	unsigned long flags;
 
 	if (! priv->has_wep)
@@ -2898,51 +3009,47 @@
 	memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
 
 	orinoco_unlock(priv, &flags);
-
-	if (erq->pointer) {
-		if (copy_to_user(erq->pointer, keybuf, xlen))
-			return -EFAULT;
-	}
-
 	return 0;
 }
 
-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setessid(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_point *erq,
+				  char *essidbuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
 	unsigned long flags;
 
 	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
 	 * anyway... - Jean II */
 
-	memset(&essidbuf, 0, sizeof(essidbuf));
-
-	if (erq->flags) {
-		/* iwconfig includes the NUL in the specified length */
-		if (erq->length > IW_ESSID_MAX_SIZE+1)
-			return -E2BIG;
-		
-		if (copy_from_user(&essidbuf, erq->pointer, erq->length))
-			return -EFAULT;
-
-		essidbuf[IW_ESSID_MAX_SIZE] = '\0';
-	}
+	/* Hum... Should not use Wireless Extension constant (may change),
+	 * should use our own... - Jean II */
+	if (erq->length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
 
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
+	/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+	/* If not ANY, get the new ESSID */
+	if (erq->flags) {
+		memcpy(priv->desired_essid, essidbuf, erq->length);
+	}
 
 	orinoco_unlock(priv, &flags);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getessid(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_point *erq,
+				  char *essidbuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
 	int active;
 	int err = 0;
 	unsigned long flags;
@@ -2956,51 +3063,46 @@
 	} else {
 		if (orinoco_lock(priv, &flags) != 0)
 			return -EBUSY;
-		memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
+		memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1);
 		orinoco_unlock(priv, &flags);
 	}
 
 	erq->flags = 1;
 	erq->length = strlen(essidbuf) + 1;
-	if (erq->pointer)
-		if (copy_to_user(erq->pointer, essidbuf, erq->length))
-			return -EFAULT;
 
 	TRACE_EXIT(dev->name);
 	
 	return 0;
 }
 
-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_setnick(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *nrq,
+				 char *nickbuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	char nickbuf[IW_ESSID_MAX_SIZE+1];
 	unsigned long flags;
 
 	if (nrq->length > IW_ESSID_MAX_SIZE)
 		return -E2BIG;
 
-	memset(nickbuf, 0, sizeof(nickbuf));
-
-	if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
-		return -EFAULT;
-
-	nickbuf[nrq->length] = '\0';
-	
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+	memset(priv->nick, 0, sizeof(priv->nick));
+	memcpy(priv->nick, nickbuf, nrq->length);
 
 	orinoco_unlock(priv, &flags);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_getnick(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *nrq,
+				 char *nickbuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	char nickbuf[IW_ESSID_MAX_SIZE+1];
 	unsigned long flags;
 
 	if (orinoco_lock(priv, &flags) != 0)
@@ -3011,23 +3113,22 @@
 
 	nrq->length = strlen(nickbuf)+1;
 
-	if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
-		return -EFAULT;
-
 	return 0;
 }
 
-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_freq *frq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int chan = -1;
 	unsigned long flags;
+	int err = -EINPROGRESS;		/* Call commit handler */
 
-	/* We can only use this in Ad-Hoc demo mode to set the operating
-	 * frequency, or in IBSS mode to set the frequency where the IBSS
-	 * will be created - Jean II */
-	if (priv->iw_mode != IW_MODE_ADHOC)
-		return -EOPNOTSUPP;
+	/* In infrastructure mode the AP sets the channel */
+	if (priv->iw_mode == IW_MODE_INFRA)
+		return -EBUSY;
 
 	if ( (frq->e == 0) && (frq->m <= 1000) ) {
 		/* Setting by channel number */
@@ -3051,13 +3152,44 @@
 
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
+
 	priv->channel = chan;
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		/* Fast channel change - no commit if successful */
+		hermes_t *hw = &priv->hw;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+					    HERMES_TEST_SET_CHANNEL,
+					chan, NULL);
+	}
 	orinoco_unlock(priv, &flags);
 
+	return err;
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_freq *frq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int tmp;
+
+	/* Locking done in there */
+	tmp = orinoco_hw_get_freq(priv);
+	if (tmp < 0) {
+		return tmp;
+	}
+
+	frq->m = tmp;
+	frq->e = 1;
+
 	return 0;
 }
 
-static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_getsens(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *srq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
@@ -3083,7 +3215,10 @@
 	return 0;
 }
 
-static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_setsens(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *srq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int val = srq->value;
@@ -3100,10 +3235,13 @@
 	priv->ap_density = val;
 	orinoco_unlock(priv, &flags);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrts(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_param *rrq,
+				char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int val = rrq->value;
@@ -3121,13 +3259,30 @@
 	priv->rts_thresh = val;
 	orinoco_unlock(priv, &flags);
 
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getrts(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_param *rrq,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	rrq->value = priv->rts_thresh;
+	rrq->disabled = (rrq->value == 2347);
+	rrq->fixed = 1;
+
 	return 0;
 }
 
-static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_setfrag(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *frq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
+	int err = -EINPROGRESS;		/* Call commit handler */
 	unsigned long flags;
 
 	if (orinoco_lock(priv, &flags) != 0)
@@ -3159,11 +3314,14 @@
 	return err;
 }
 
-static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_getfrag(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *frq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
-	int err = 0;
+	int err;
 	u16 val;
 	unsigned long flags;
 
@@ -3196,10 +3354,12 @@
 	return err;
 }
 
-static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrate(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *rrq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
 	int ratemode = -1;
 	int bitrate; /* 100s of kilobits */
 	int i;
@@ -3235,10 +3395,13 @@
 	priv->bitratemode = ratemode;
 	orinoco_unlock(priv, &flags);
 
-	return err;
+	return -EINPROGRESS;
 }
 
-static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getrate(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *rrq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
@@ -3303,10 +3466,13 @@
 	return err;
 }
 
-static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_setpower(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *prq,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
+	int err = -EINPROGRESS;		/* Call commit handler */
 	unsigned long flags;
 
 	if (orinoco_lock(priv, &flags) != 0)
@@ -3355,7 +3521,10 @@
 	return err;
 }
 
-static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_getpower(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *prq,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
@@ -3403,7 +3572,10 @@
 	return err;
 }
 
-static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getretry(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *rrq,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
@@ -3454,10 +3626,38 @@
 	return err;
 }
 
-static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_reset(struct net_device *dev,
+			       struct iw_request_info *info,
+			       void *wrqu,
+			       char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int val = *( (int *) wrq->u.name );
+
+	if (! capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
+		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+
+		/* Firmware reset */
+		orinoco_reset(dev);
+	} else {
+		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+
+		schedule_work(&priv->reset_work);
+	}
+
+	return 0;
+}
+
+static int orinoco_ioctl_setibssport(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int val = *( (int *) extra );
 	unsigned long flags;
 
 	if (orinoco_lock(priv, &flags) != 0)
@@ -3469,28 +3669,28 @@
 	set_port_type(priv);
 
 	orinoco_unlock(priv, &flags);
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getibssport(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int *val = (int *)wrq->u.name;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
+	int *val = (int *) extra;
 
 	*val = priv->ibss_port;
-	orinoco_unlock(priv, &flags);
-
 	return 0;
 }
 
-static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_setport3(struct net_device *dev,
+				  struct iw_request_info *info,
+				  void *wrqu,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int val = *( (int *) wrq->u.name );
+	int val = *( (int *) extra );
 	int err = 0;
 	unsigned long flags;
 
@@ -3519,51 +3719,131 @@
 		err = -EINVAL;
 	}
 
-	if (! err)
+	if (! err) {
 		/* Actually update the mode we are using */
 		set_port_type(priv);
+		err = -EINPROGRESS;
+	}
 
 	orinoco_unlock(priv, &flags);
 
 	return err;
 }
 
-static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getport3(struct net_device *dev,
+				  struct iw_request_info *info,
+				  void *wrqu,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int *val = (int *)wrq->u.name;
+	int *val = (int *) extra;
+
+	*val = priv->prefer_port3;
+	return 0;
+}
+
+static int orinoco_ioctl_setpreamble(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
 	unsigned long flags;
+	int val;
+
+	if (! priv->has_preamble)
+		return -EOPNOTSUPP;
+
+	/* 802.11b has recently defined some short preamble.
+	 * Basically, the Phy header has been reduced in size.
+	 * This increase performance, especially at high rates
+	 * (the preamble is transmitted at 1Mb/s), unfortunately
+	 * this give compatibility troubles... - Jean II */
+	val = *( (int *) extra );
 
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	*val = priv->prefer_port3;
+	if (val)
+		priv->preamble = 1;
+	else
+		priv->preamble = 0;
+
 	orinoco_unlock(priv, &flags);
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getpreamble(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int *val = (int *) extra;
+
+	if (! priv->has_preamble)
+		return -EOPNOTSUPP;
+
+	*val = priv->preamble;
 	return 0;
 }
 
+/* ioctl interface to hermes_read_ltv()
+ * To use with iwpriv, pass the RID as the token argument, e.g.
+ * iwpriv get_rid [0xfc00]
+ * At least Wireless Tools 25 is required to use iwpriv.
+ * For Wireless Tools 25 and 26 append "dummy" are the end. */
+static int orinoco_ioctl_getrid(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_point *data,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int rid = data->flags;
+	u16 length;
+	int err;
+	unsigned long flags;
+
+	/* It's a "get" function, but we don't want users to access the
+	 * WEP key and other raw firmware data */
+	if (! capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (rid < 0xfc00 || rid > 0xffff)
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+			      extra);
+	if (err)
+		goto out;
+
+	data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
+			     MAX_RID_LEN);
+
+ out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
 /* Spy is used for link quality/strength measurements in Ad-Hoc mode
  * Jean II */
-static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_setspy(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_point *srq,
+				char *extra)
+
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	struct sockaddr address[IW_MAX_SPY];
+	struct sockaddr *address = (struct sockaddr *) extra;
 	int number = srq->length;
 	int i;
-	int err = 0;
 	unsigned long flags;
 
-	/* Check the number of addresses */
-	if (number > IW_MAX_SPY)
-		return -E2BIG;
-
-	/* Get the data in the driver */
-	if (srq->pointer) {
-		if (copy_from_user(address, srq->pointer,
-				   sizeof(struct sockaddr) * number))
-			return -EFAULT;
-	}
-
 	/* Make sure nobody mess with the structure while we do */
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
@@ -3587,14 +3867,17 @@
 	/* Now, let the others play */
 	orinoco_unlock(priv, &flags);
 
-	return err;
+	/* Do NOT call commit handler */
+	return 0;
 }
 
-static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_getspy(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_point *srq,
+				char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	struct sockaddr address[IW_MAX_SPY];
-	struct iw_quality spy_stat[IW_MAX_SPY];
+	struct sockaddr *address = (struct sockaddr *) extra;
 	int number;
 	int i;
 	unsigned long flags;
@@ -3603,7 +3886,12 @@
 		return -EBUSY;
 
 	number = priv->spy_number;
-	if ((number > 0) && (srq->pointer)) {
+	/* Create address struct */
+	for (i = 0; i < number; i++) {
+		memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN);
+		address[i].sa_family = AF_UNIX;
+	}
+	if (number > 0) {
 		/* Create address struct */
 		for (i = 0; i < number; i++) {
 			memcpy(address[i].sa_data, priv->spy_address[i],
@@ -3614,344 +3902,503 @@
 		/* In theory, we should disable irqs while copying the stats
 		 * because the rx path might update it in the middle...
 		 * Bah, who care ? - Jean II */
-		memcpy(&spy_stat, priv->spy_stat,
-		       sizeof(struct iw_quality) * IW_MAX_SPY);
-		for (i=0; i < number; i++)
-			priv->spy_stat[i].updated = 0;
+		memcpy(extra  + (sizeof(struct sockaddr) * number),
+		       priv->spy_stat, sizeof(struct iw_quality) * number);
 	}
+	/* Reset updated flags. */
+	for (i = 0; i < number; i++)
+		priv->spy_stat[i].updated = 0;
 
 	orinoco_unlock(priv, &flags);
 
-	/* Push stuff to user space */
 	srq->length = number;
-	if(copy_to_user(srq->pointer, address,
-			 sizeof(struct sockaddr) * number))
-		return -EFAULT;
-	if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
-			&spy_stat, sizeof(struct iw_quality) * number))
-		return -EFAULT;
 
 	return 0;
 }
 
-static int
-orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+/* Trigger a scan (look for other cells in the vicinity */
+static int orinoco_ioctl_setscan(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *srq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	struct iwreq *wrq = (struct iwreq *)rq;
+	hermes_t *hw = &priv->hw;
 	int err = 0;
-	int tmp;
-	int changed = 0;
 	unsigned long flags;
 
-	TRACE_ENTER(dev->name);
+	/* Note : you may have realised that, as this is a SET operation,
+	 * this is priviledged and therefore a normal user can't
+	 * perform scanning.
+	 * This is not an error, while the device perform scanning,
+	 * traffic doesn't flow, so it's a perfect DoS...
+	 * Jean II */
 
-	/* In theory, we could allow most of the the SET stuff to be
-	 * done. In practice, the lapse of time at startup when the
-	 * card is not ready is very short, so why bother...  Note
-	 * that netif_device_present is different from up/down
-	 * (ifconfig), when the device is not yet up, it is usually
-	 * already ready...  Jean II */
-	if (! netif_device_present(dev))
-		return -ENODEV;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
-	switch (cmd) {
-	case SIOCGIWNAME:
-		strcpy(wrq->u.name, "IEEE 802.11-DS");
-		break;
-		
-	case SIOCGIWAP:
-		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-		err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
-		break;
-
-	case SIOCGIWRANGE:
-		err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
-		break;
-
-	case SIOCSIWMODE:
-		if (orinoco_lock(priv, &flags) != 0)
-			return -EBUSY;
-		switch (wrq->u.mode) {
-		case IW_MODE_ADHOC:
-			if (! (priv->has_ibss || priv->has_port3) )
-				err = -EINVAL;
-			else {
-				priv->iw_mode = IW_MODE_ADHOC;
-				changed = 1;
-			}
-			break;
-
-		case IW_MODE_INFRA:
-			priv->iw_mode = IW_MODE_INFRA;
-			changed = 1;
-			break;
-
-		default:
-			err = -EINVAL;
-			break;
-		}
-		set_port_type(priv);
-		orinoco_unlock(priv, &flags);
-		break;
-
-	case SIOCGIWMODE:
-		if (orinoco_lock(priv, &flags) != 0)
-			return -EBUSY;
-		wrq->u.mode = priv->iw_mode;
-		orinoco_unlock(priv, &flags);
-		break;
-
-	case SIOCSIWENCODE:
-		err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWENCODE:
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding);
-		break;
-
-	case SIOCSIWESSID:
-		err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWESSID:
-		err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
-		break;
-
-	case SIOCSIWNICKN:
-		err = orinoco_ioctl_setnick(dev, &wrq->u.data);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWNICKN:
-		err = orinoco_ioctl_getnick(dev, &wrq->u.data);
-		break;
-
-	case SIOCGIWFREQ:
-		tmp = orinoco_hw_get_freq(priv);
-		if (tmp < 0) {
-			err = tmp;
-		} else {
-			wrq->u.freq.m = tmp;
-			wrq->u.freq.e = 1;
-		}
-		break;
-
-	case SIOCSIWFREQ:
-		err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWSENS:
-		err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
-		break;
-
-	case SIOCSIWSENS:
-		err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWRTS:
-		wrq->u.rts.value = priv->rts_thresh;
-		wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
-		wrq->u.rts.fixed = 1;
-		break;
-
-	case SIOCSIWRTS:
-		err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCSIWFRAG:
-		err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWFRAG:
-		err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
-		break;
-
-	case SIOCSIWRATE:
-		err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWRATE:
-		err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
-		break;
-
-	case SIOCSIWPOWER:
-		err = orinoco_ioctl_setpower(dev, &wrq->u.power);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWPOWER:
-		err = orinoco_ioctl_getpower(dev, &wrq->u.power);
-		break;
-
-	case SIOCGIWTXPOW:
-		/* The card only supports one tx power, so this is easy */
-		wrq->u.txpower.value = 15; /* dBm */
-		wrq->u.txpower.fixed = 1;
-		wrq->u.txpower.disabled = 0;
-		wrq->u.txpower.flags = IW_TXPOW_DBM;
-		break;
-
-	case SIOCSIWRETRY:
-		err = -EOPNOTSUPP;
-		break;
-
-	case SIOCGIWRETRY:
-		err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
-		break;
-
-	case SIOCSIWSPY:
-		err = orinoco_ioctl_setspy(dev, &wrq->u.data);
-		break;
-
-	case SIOCGIWSPY:
-		err = orinoco_ioctl_getspy(dev, &wrq->u.data);
-		break;
-
-	case SIOCGIWPRIV:
-		if (wrq->u.data.pointer) {
-			struct iw_priv_args privtab[] = {
-				{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
-				{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
-				{ SIOCIWFIRSTPRIV + 0x2,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_port3" },
-				{ SIOCIWFIRSTPRIV + 0x3, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_port3" },
-				{ SIOCIWFIRSTPRIV + 0x4,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_preamble" },
-				{ SIOCIWFIRSTPRIV + 0x5, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_preamble" },
-				{ SIOCIWFIRSTPRIV + 0x6,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_ibssport" },
-				{ SIOCIWFIRSTPRIV + 0x7, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_ibssport" },
-			};
-
-			wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
-			if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
-				err = -EFAULT;
-		}
-		break;
-	       
-	case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
-	case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-		
-		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
-
-		schedule_work(&priv->reset_work);
-		break;
-
-	case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		err = orinoco_ioctl_setport3(dev, wrq);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
-		err = orinoco_ioctl_getport3(dev, wrq);
-		break;
-
-	case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		/* 802.11b has recently defined some short preamble.
-		 * Basically, the Phy header has been reduced in size.
-		 * This increase performance, especially at high rates
-		 * (the preamble is transmitted at 1Mb/s), unfortunately
-		 * this give compatibility troubles... - Jean II */
-		if(priv->has_preamble) {
-			int val = *( (int *) wrq->u.name );
-
-			if (orinoco_lock(priv, &flags) != 0)
-				return -EBUSY;
-			if (val)
-				priv->preamble = 1;
-			else
-				priv->preamble = 0;
-			orinoco_unlock(priv, &flags);
-			changed = 1;
-		} else
-			err = -EOPNOTSUPP;
-		break;
-
-	case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
-		if(priv->has_preamble) {
-			int *val = (int *)wrq->u.name;
-
-			if (orinoco_lock(priv, &flags) != 0)
-				return -EBUSY;
-			*val = priv->preamble;
-			orinoco_unlock(priv, &flags);
-		} else
-			err = -EOPNOTSUPP;
-		break;
-	case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		err = orinoco_ioctl_setibssport(dev, wrq);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
-		err = orinoco_ioctl_getibssport(dev, wrq);
-		break;
-
-	default:
-		err = -EOPNOTSUPP;
+	/* Scanning with port 0 disabled would fail */
+	if (!netif_running(dev)) {
+		err = -ENETDOWN;
+		goto out;
 	}
-	
-	if (! err && changed && netif_running(dev)) {
-		err = orinoco_reconfigure(dev);
-	}		
 
-	TRACE_EXIT(dev->name);
+	/* In monitor mode, the scan results are always empty.
+	 * Probe responses are passed to the driver as received
+	 * frames and could be processed in software. */
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
 
+	/* Note : because we don't lock out the irq handler, the way
+	 * we access scan variables in priv is critical.
+	 *	o scan_inprogress : not touched by irq handler
+	 *	o scan_mode : not touched by irq handler
+	 *	o scan_result : irq is strict producer, non-irq is strict
+	 *		consumer.
+	 *	o scan_len : synchronised with scan_result
+	 * Before modifying anything on those variables, please think hard !
+	 * Jean II */
+
+	/* If there is still some left-over scan results, get rid of it */
+	if (priv->scan_result != NULL) {
+		/* What's likely is that a client did crash or was killed
+		 * between triggering the scan request and reading the
+		 * results, so we need to reset everything.
+		 * Some clients that are too slow may suffer from that...
+		 * Jean II */
+		kfree(priv->scan_result);
+		priv->scan_result = NULL;
+	}
+
+	/* Save flags */
+	priv->scan_mode = srq->flags;
+
+	/* Always trigger scanning, even if it's in progress.
+	 * This way, if the info frame get lost, we will recover somewhat
+	 * gracefully  - Jean II */
+
+	if (priv->has_hostscan) {
+		switch (priv->firmware_type) {
+		case FIRMWARE_TYPE_SYMBOL:
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFHOSTSCAN_SYMBOL,
+						   HERMES_HOSTSCAN_SYMBOL_ONCE |
+						   HERMES_HOSTSCAN_SYMBOL_BCAST);
+			break;
+		case FIRMWARE_TYPE_INTERSIL: {
+			u16 req[3];
+
+			req[0] = cpu_to_le16(0x3fff);	/* All channels */
+			req[1] = cpu_to_le16(0x0001);	/* rate 1 Mbps */
+			req[2] = 0;			/* Any ESSID */
+			err = HERMES_WRITE_RECORD(hw, USER_BAP,
+						  HERMES_RID_CNFHOSTSCAN, &req);
+		}
+		break;
+		case FIRMWARE_TYPE_AGERE:
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFSCANSSID_AGERE,
+						   0);	/* Any ESSID */
+			if (err)
+				break;
+
+			err = hermes_inquire(hw, HERMES_INQ_SCAN);
+			break;
+		}
+	} else
+		err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+	/* One more client */
+	if (! err)
+		priv->scan_inprogress = 1;
+
+ out:
+	orinoco_unlock(priv, &flags);
 	return err;
 }
 
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline int orinoco_translate_scan(struct net_device *dev,
+					 char *buffer,
+					 char *scan,
+					 int scan_len)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int			offset;		/* In the scan data */
+	union hermes_scan_info *atom;
+	int			atom_len;
+	u16			capabilities;
+	u16			channel;
+	struct iw_event		iwe;		/* Temporary buffer */
+	char *			current_ev = buffer;
+	char *			end_buf = buffer + IW_SCAN_MAX_DATA;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		atom_len = sizeof(struct agere_scan_apinfo);
+ 		offset = 0;
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		/* Lack of documentation necessitates this hack.
+		 * Different firmwares have 68 or 76 byte long atoms.
+		 * We try modulo first.  If the length divides by both,
+		 * we check what would be the channel in the second
+		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
+		 * Valid channel cannot be 0.  */
+		if (scan_len % 76)
+			atom_len = 68;
+		else if (scan_len % 68)
+			atom_len = 76;
+		else if (scan_len >= 1292 && scan[68] == 0)
+			atom_len = 76;
+		else
+			atom_len = 68;
+		offset = 0;
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		offset = 4;
+		if (priv->has_hostscan)
+			atom_len = scan[0] + (scan[1] << 8);
+		else
+			atom_len = offsetof(struct prism2_scan_apinfo, atim);
+		break;
+	default:
+		return 0;
+	}
+
+	/* Check that we got an whole number of atoms */
+	if ((scan_len - offset) % atom_len) {
+		printk(KERN_ERR "%s: Unexpected scan data length %d, "
+		       "atom_len %d, offset %d\n", dev->name, scan_len,
+		       atom_len, offset);
+		return 0;
+	}
+
+	/* Read the entries one by one */
+	for (; offset + atom_len <= scan_len; offset += atom_len) {
+		/* Get next atom */
+		atom = (union hermes_scan_info *) (scan + offset);
+
+		/* First entry *MUST* be the AP MAC address */
+		iwe.cmd = SIOCGIWAP;
+		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+		memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
+		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+		/* Other entries will be displayed in the order we give them */
+
+		/* Add the ESSID */
+		iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
+		if (iwe.u.data.length > 32)
+			iwe.u.data.length = 32;
+		iwe.cmd = SIOCGIWESSID;
+		iwe.u.data.flags = 1;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+		/* Add mode */
+		iwe.cmd = SIOCGIWMODE;
+		capabilities = le16_to_cpu(atom->a.capabilities);
+		if (capabilities & 0x3) {
+			if (capabilities & 0x1)
+				iwe.u.mode = IW_MODE_MASTER;
+			else
+				iwe.u.mode = IW_MODE_ADHOC;
+			current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+		}
+
+		channel = atom->s.channel;
+		if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
+			/* Add frequency */
+			iwe.cmd = SIOCGIWFREQ;
+			iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+			iwe.u.freq.e = 1;
+			current_ev = iwe_stream_add_event(current_ev, end_buf,
+							  &iwe, IW_EV_FREQ_LEN);
+		}
+
+		/* Add quality statistics */
+		iwe.cmd = IWEVQUAL;
+		iwe.u.qual.updated = 0x10;	/* no link quality */
+		iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
+		iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
+		/* Wireless tools prior to 27.pre22 will show link quality
+		 * anyway, so we provide a reasonable value. */
+		if (iwe.u.qual.level > iwe.u.qual.noise)
+			iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+		else
+			iwe.u.qual.qual = 0;
+		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+		/* Add encryption capability */
+		iwe.cmd = SIOCGIWENCODE;
+		if (capabilities & 0x10)
+			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+		else
+			iwe.u.data.flags = IW_ENCODE_DISABLED;
+		iwe.u.data.length = 0;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+		/* Bit rate is not available in Lucent/Agere firmwares */
+		if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+			char *	current_val = current_ev + IW_EV_LCP_LEN;
+			int	i;
+			int	step;
+
+			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+				step = 2;
+			else
+				step = 1;
+
+			iwe.cmd = SIOCGIWRATE;
+			/* Those two flags are ignored... */
+			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+			/* Max 10 values */
+			for (i = 0; i < 10; i += step) {
+				/* NULL terminated */
+				if (atom->p.rates[i] == 0x0)
+					break;
+				/* Bit rate given in 500 kb/s units (+ 0x80) */
+				iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
+				current_val = iwe_stream_add_value(current_ev, current_val,
+								   end_buf, &iwe,
+								   IW_EV_PARAM_LEN);
+			}
+			/* Check if we added any event */
+			if ((current_val - current_ev) > IW_EV_LCP_LEN)
+				current_ev = current_val;
+		}
+
+		/* The other data in the scan result are not really
+		 * interesting, so for now drop it - Jean II */
+	}
+	return current_ev - buffer;
+}
+
+/* Return results of a scan */
+static int orinoco_ioctl_getscan(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *srq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* If no results yet, ask to try again later */
+	if (priv->scan_result == NULL) {
+		if (priv->scan_inprogress)
+			/* Important note : we don't want to block the caller
+			 * until results are ready for various reasons.
+			 * First, managing wait queues is complex and racy.
+			 * Second, we grab some rtnetlink lock before comming
+			 * here (in dev_ioctl()).
+			 * Third, we generate an Wireless Event, so the
+			 * caller can wait itself on that - Jean II */
+			err = -EAGAIN;
+		else
+			/* Client error, no scan results...
+			 * The caller need to restart the scan. */
+			err = -ENODATA;
+	} else {
+		/* We have some results to push back to user space */
+
+		/* Translate to WE format */
+		srq->length = orinoco_translate_scan(dev, extra,
+						     priv->scan_result,
+						     priv->scan_len);
+
+		/* Return flags */
+		srq->flags = (__u16) priv->scan_mode;
+
+		/* Results are here, so scan no longer in progress */
+		priv->scan_inprogress = 0;
+
+		/* In any case, Scan results will be cleaned up in the
+		 * reset function and when exiting the driver.
+		 * The person triggering the scanning may never come to
+		 * pick the results, so we need to do it in those places.
+		 * Jean II */
+
+#ifdef SCAN_SINGLE_READ
+		/* If you enable this option, only one client (the first
+		 * one) will be able to read the result (and only one
+		 * time). If there is multiple concurent clients that
+		 * want to read scan results, this behavior is not
+		 * advisable - Jean II */
+		kfree(priv->scan_result);
+		priv->scan_result = NULL;
+#endif /* SCAN_SINGLE_READ */
+		/* Here, if too much time has elapsed since last scan,
+		 * we may want to clean up scan results... - Jean II */
+	}
+	  
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+/* Commit handler, called after set operations */
+static int orinoco_ioctl_commit(struct net_device *dev,
+				struct iw_request_info *info,
+				void *wrqu,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	unsigned long flags;
+	int err = 0;
+
+	if (!priv->open)
+		return 0;
+
+	if (priv->broken_disableport) {
+		orinoco_reset(dev);
+		return 0;
+	}
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return err;
+
+	err = hermes_disable_port(hw, 0);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to disable port "
+		       "while reconfiguring card\n", dev->name);
+		priv->broken_disableport = 1;
+		goto out;
+	}
+
+	err = __orinoco_program_rids(dev);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+		       dev->name);
+		goto out;
+	}
+
+	err = hermes_enable_port(hw, 0);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+		       dev->name);
+		goto out;
+	}
+
+ out:
+	if (err) {
+		printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+		schedule_work(&priv->reset_work);
+		err = 0;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static const struct iw_priv_args orinoco_privtab[] = {
+	{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+	{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+	{ SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_port3" },
+	{ SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_port3" },
+	{ SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_preamble" },
+	{ SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_preamble" },
+	{ SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_ibssport" },
+	{ SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_ibssport" },
+	{ SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
+	  "get_rid" },
+};
+
+
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+static const iw_handler	orinoco_handler[] = {
+	[SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit,
+	[SIOCGIWNAME  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname,
+	[SIOCSIWFREQ  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq,
+	[SIOCGIWFREQ  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq,
+	[SIOCSIWMODE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode,
+	[SIOCGIWMODE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode,
+	[SIOCSIWSENS  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens,
+	[SIOCGIWSENS  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens,
+	[SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange,
+	[SIOCSIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy,
+	[SIOCGIWSPY   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
+	[SIOCSIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
+	[SIOCGIWAP    -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
+	[SIOCSIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
+	[SIOCGIWSCAN  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
+	[SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
+	[SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
+	[SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
+	[SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick,
+	[SIOCSIWRATE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate,
+	[SIOCGIWRATE  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate,
+	[SIOCSIWRTS   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts,
+	[SIOCGIWRTS   -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts,
+	[SIOCSIWFRAG  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag,
+	[SIOCGIWFRAG  -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag,
+	[SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry,
+	[SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode,
+	[SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode,
+	[SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower,
+	[SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower,
+};
+
+
+/*
+  Added typecasting since we no longer use iwreq_data -- Moustafa
+ */
+static const iw_handler	orinoco_private_handler[] = {
+	[0] (iw_handler) orinoco_ioctl_reset,
+	[1] (iw_handler) orinoco_ioctl_reset,
+	[2] (iw_handler) orinoco_ioctl_setport3,
+	[3] (iw_handler) orinoco_ioctl_getport3,
+	[4] (iw_handler) orinoco_ioctl_setpreamble,
+	[5] (iw_handler) orinoco_ioctl_getpreamble,
+	[6] (iw_handler) orinoco_ioctl_setibssport,
+	[7] (iw_handler) orinoco_ioctl_getibssport,
+	[9] (iw_handler) orinoco_ioctl_getrid,
+};
+
+static const struct iw_handler_def orinoco_handler_def = {
+	.num_standard = ARRAY_SIZE(orinoco_handler),
+	.num_private = ARRAY_SIZE(orinoco_private_handler),
+	.num_private_args = ARRAY_SIZE(orinoco_privtab),
+	.standard = orinoco_handler,
+	.private = orinoco_private_handler,
+	.private_args = orinoco_privtab,
+};
+
+static void orinoco_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *info)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
+	strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+	strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
+	if (dev->class_dev.dev)
+		strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+			sizeof(info->bus_info) - 1);
+	else
+		snprintf(info->bus_info, sizeof(info->bus_info) - 1,
+			 "PCMCIA %p", priv->hw.iobase);
+}
+
+static struct ethtool_ops orinoco_ethtool_ops = {
+	.get_drvinfo = orinoco_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};
 
 /********************************************************************/
 /* Debugging                                                        */
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index f749b50..2f213a7 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -7,7 +7,7 @@
 #ifndef _ORINOCO_H
 #define _ORINOCO_H
 
-#define DRIVER_VERSION "0.14alpha2"
+#define DRIVER_VERSION "0.15rc2"
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
@@ -22,6 +22,8 @@
 
 #define WIRELESS_SPY		// enable iwspy support
 
+#define MAX_SCAN_LEN		4096
+
 #define ORINOCO_MAX_KEY_SIZE	14
 #define ORINOCO_MAX_KEYS	4
 
@@ -30,6 +32,20 @@
 	char data[ORINOCO_MAX_KEY_SIZE];
 } __attribute__ ((packed));
 
+struct header_struct {
+	/* 802.3 */
+	u8 dest[ETH_ALEN];
+	u8 src[ETH_ALEN];
+	u16 len;
+	/* 802.2 */
+	u8 dsap;
+	u8 ssap;
+	u8 ctrl;
+	/* SNAP */
+	u8 oui[3];
+	u16 ethertype;
+} __attribute__ ((packed));
+
 typedef enum {
 	FIRMWARE_TYPE_AGERE,
 	FIRMWARE_TYPE_INTERSIL,
@@ -48,6 +64,8 @@
 	/* driver state */
 	int open;
 	u16 last_linkstatus;
+	struct work_struct join_work;
+	struct work_struct wevent_work;
 
 	/* Net device stuff */
 	struct net_device *ndev;
@@ -74,7 +92,9 @@
 	unsigned int has_pm:1;
 	unsigned int has_preamble:1;
 	unsigned int has_sensitivity:1;
+	unsigned int has_hostscan:1;
 	unsigned int broken_disableport:1;
+	unsigned int broken_monitor:1;
 
 	/* Configuration paramaters */
 	u32 iw_mode;
@@ -84,6 +104,8 @@
 	int bitratemode;
  	char nick[IW_ESSID_MAX_SIZE+1];
 	char desired_essid[IW_ESSID_MAX_SIZE+1];
+	char desired_bssid[ETH_ALEN];
+	int bssid_fixed;
 	u16 frag_thresh, mwo_robust;
 	u16 channel;
 	u16 ap_density, rts_thresh;
@@ -98,6 +120,12 @@
 	/* Configuration dependent variables */
 	int port_type, createibss;
 	int promiscuous, mc_count;
+
+	/* Scanning support */
+	int	scan_inprogress;	/* Scan pending... */
+	u32	scan_mode;		/* Type of scan done */
+	char *	scan_result;		/* Result of previous scan */
+	int	scan_len;		/* Lenght of result */
 };
 
 #ifdef ORINOCO_DEBUG
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
index 4481ec1..adc7499 100644
--- a/drivers/net/wireless/prism54/isl_38xx.c
+++ b/drivers/net/wireless/prism54/isl_38xx.c
@@ -112,10 +112,10 @@
 void
 isl38xx_trigger_device(int asleep, void __iomem *device_base)
 {
-	struct timeval current_time;
 	u32 reg, counter = 0;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
+	struct timeval current_time;
 	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
 #endif
 
@@ -126,11 +126,11 @@
 		do_gettimeofday(&current_time);
 		DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
 		      current_time.tv_sec, (long)current_time.tv_usec);
-#endif
 
 		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
 		      current_time.tv_sec, (long)current_time.tv_usec,
 		      readl(device_base + ISL38XX_CTRL_STAT_REG));
+#endif
 		udelay(ISL38XX_WRITEIO_DELAY);
 
 		reg = readl(device_base + ISL38XX_INT_IDENT_REG);
@@ -148,10 +148,12 @@
 				counter++;
 			}
 
+#if VERBOSE > SHOW_ERROR_MESSAGES
 			DEBUG(SHOW_TRACING,
 			      "%08li.%08li Device register read %08x\n",
 			      current_time.tv_sec, (long)current_time.tv_usec,
 			      readl(device_base + ISL38XX_CTRL_STAT_REG));
+#endif
 			udelay(ISL38XX_WRITEIO_DELAY);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 7a4adc4..794fb55 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1176,8 +1176,12 @@
 		n_sectors = ata_id_u32(args->id, 60);
 	n_sectors--;		/* ATA TotalUserSectors - 1 */
 
-	tmp = n_sectors;	/* note: truncates, if lba48 */
 	if (args->cmd->cmnd[0] == READ_CAPACITY) {
+		if( n_sectors >= 0xffffffffULL )
+			tmp = 0xffffffff ;  /* Return max count on overflow */
+		else
+			tmp = n_sectors ;
+
 		/* sector count, 32-bit */
 		rbuf[0] = tmp >> (8 * 3);
 		rbuf[1] = tmp >> (8 * 2);
@@ -1191,10 +1195,12 @@
 
 	} else {
 		/* sector count, 64-bit */
-		rbuf[2] = n_sectors >> (8 * 7);
-		rbuf[3] = n_sectors >> (8 * 6);
-		rbuf[4] = n_sectors >> (8 * 5);
-		rbuf[5] = n_sectors >> (8 * 4);
+		tmp = n_sectors >> (8 * 4);
+		rbuf[2] = tmp >> (8 * 3);
+		rbuf[3] = tmp >> (8 * 2);
+		rbuf[4] = tmp >> (8 * 1);
+		rbuf[5] = tmp;
+		tmp = n_sectors;
 		rbuf[6] = tmp >> (8 * 3);
 		rbuf[7] = tmp >> (8 * 2);
 		rbuf[8] = tmp >> (8 * 1);
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index feb8e73..d27fb4c 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -1497,23 +1497,6 @@
 	return 0;
 }
 
-
-
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* SPARC: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
-	return -1;
-}
-
-void unregister_serial(int line)
-{
-	return;
-}
-	
 module_init(rs68328_init);
 
 
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index d8b9d2b..34e75bc 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -77,23 +77,9 @@
  */
 #define is_real_interrupt(irq)	((irq) != 0)
 
-/*
- * This converts from our new CONFIG_ symbols to the symbols
- * that asm/serial.h expects.  You _NEED_ to comment out the
- * linux/config.h include contained inside asm/serial.h for
- * this to work.
- */
-#undef CONFIG_SERIAL_MANY_PORTS
-#undef CONFIG_SERIAL_DETECT_IRQ
-#undef CONFIG_SERIAL_MULTIPORT
-#undef CONFIG_HUB6
-
 #ifdef CONFIG_SERIAL_8250_DETECT_IRQ
 #define CONFIG_SERIAL_DETECT_IRQ 1
 #endif
-#ifdef CONFIG_SERIAL_8250_MULTIPORT
-#define CONFIG_SERIAL_MULTIPORT 1
-#endif
 #ifdef CONFIG_SERIAL_8250_MANY_PORTS
 #define CONFIG_SERIAL_MANY_PORTS 1
 #endif
@@ -2323,10 +2309,11 @@
 {
 	struct plat_serial8250_port *p = dev->platform_data;
 	struct uart_port port;
+	int ret, i;
 
 	memset(&port, 0, sizeof(struct uart_port));
 
-	for (; p && p->flags != 0; p++) {
+	for (i = 0; p && p->flags != 0; p++, i++) {
 		port.iobase	= p->iobase;
 		port.membase	= p->membase;
 		port.irq	= p->irq;
@@ -2335,10 +2322,16 @@
 		port.iotype	= p->iotype;
 		port.flags	= p->flags;
 		port.mapbase	= p->mapbase;
+		port.hub6	= p->hub6;
 		port.dev	= dev;
 		if (share_irqs)
 			port.flags |= UPF_SHARE_IRQ;
-		serial8250_register_port(&port);
+		ret = serial8250_register_port(&port);
+		if (ret < 0) {
+			dev_err(dev, "unable to register port at index %d "
+				"(IO%lx MEM%lx IRQ%d): %d\n", i,
+				p->iobase, p->mapbase, p->irq, ret);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/serial/8250_accent.c b/drivers/serial/8250_accent.c
new file mode 100644
index 0000000..1f2c276
--- /dev/null
+++ b/drivers/serial/8250_accent.c
@@ -0,0 +1,47 @@
+/*
+ *  linux/drivers/serial/8250_accent.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)				\
+	{						\
+		.iobase		= _base,		\
+		.irq		= _irq,			\
+		.uartclk	= 1843200,		\
+		.iotype		= UPIO_PORT,		\
+		.flags		= UPF_BOOT_AUTOCONF,	\
+	}
+
+static struct plat_serial8250_port accent_data[] = {
+	PORT(0x330, 4),
+	PORT(0x338, 4),
+	{ },
+};
+
+static struct platform_device accent_device = {
+	.name			= "serial8250",
+	.id			= 2,
+	.dev			= {
+		.platform_data	= accent_data,
+	},
+};
+
+static int __init accent_init(void)
+{
+	return platform_device_register(&accent_device);
+}
+
+module_init(accent_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_boca.c b/drivers/serial/8250_boca.c
new file mode 100644
index 0000000..465c9ea
--- /dev/null
+++ b/drivers/serial/8250_boca.c
@@ -0,0 +1,61 @@
+/*
+ *  linux/drivers/serial/8250_boca.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)				\
+	{						\
+		.iobase		= _base,		\
+		.irq		= _irq,			\
+		.uartclk	= 1843200,		\
+		.iotype		= UPIO_PORT,		\
+		.flags		= UPF_BOOT_AUTOCONF,	\
+	}
+
+static struct plat_serial8250_port boca_data[] = {
+	PORT(0x100, 12),
+	PORT(0x108, 12),
+	PORT(0x110, 12),
+	PORT(0x118, 12),
+	PORT(0x120, 12),
+	PORT(0x128, 12),
+	PORT(0x130, 12),
+	PORT(0x138, 12),
+	PORT(0x140, 12),
+	PORT(0x148, 12),
+	PORT(0x150, 12),
+	PORT(0x158, 12),
+	PORT(0x160, 12),
+	PORT(0x168, 12),
+	PORT(0x170, 12),
+	PORT(0x178, 12),
+	{ },
+};
+
+static struct platform_device boca_device = {
+	.name			= "serial8250",
+	.id			= 3,
+	.dev			= {
+		.platform_data	= boca_data,
+	},
+};
+
+static int __init boca_init(void)
+{
+	return platform_device_register(&boca_device);
+}
+
+module_init(boca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Boca cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_fourport.c b/drivers/serial/8250_fourport.c
new file mode 100644
index 0000000..e9b4d90
--- /dev/null
+++ b/drivers/serial/8250_fourport.c
@@ -0,0 +1,53 @@
+/*
+ *  linux/drivers/serial/8250_fourport.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)						\
+	{								\
+		.iobase		= _base,				\
+		.irq		= _irq,					\
+		.uartclk	= 1843200,				\
+		.iotype		= UPIO_PORT,				\
+		.flags		= UPF_BOOT_AUTOCONF | UPF_FOURPORT,	\
+	}
+
+static struct plat_serial8250_port fourport_data[] = {
+	PORT(0x1a0, 9),
+	PORT(0x1a8, 9),
+	PORT(0x1b0, 9),
+	PORT(0x1b8, 9),
+	PORT(0x2a0, 5),
+	PORT(0x2a8, 5),
+	PORT(0x2b0, 5),
+	PORT(0x2b8, 5),
+	{ },
+};
+
+static struct platform_device fourport_device = {
+	.name			= "serial8250",
+	.id			= 1,
+	.dev			= {
+		.platform_data	= fourport_data,
+	},
+};
+
+static int __init fourport_init(void)
+{
+	return platform_device_register(&fourport_device);
+}
+
+module_init(fourport_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c
new file mode 100644
index 0000000..77f396f
--- /dev/null
+++ b/drivers/serial/8250_hub6.c
@@ -0,0 +1,58 @@
+/*
+ *  linux/drivers/serial/8250_hub6.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define HUB6(card,port)							\
+	{								\
+		.iobase		= 0x302,				\
+		.irq		= 3,					\
+		.uartclk	= 1843200,				\
+		.iotype		= UPIO_HUB6,				\
+		.flags		= UPF_BOOT_AUTOCONF,			\
+		.hub6		= (card) << 6 | (port) << 3 | 1,	\
+	}
+
+static struct plat_serial8250_port hub6_data[] = {
+	HUB6(0,0),
+	HUB6(0,1),
+	HUB6(0,2),
+	HUB6(0,3),
+	HUB6(0,4),
+	HUB6(0,5),
+	HUB6(1,0),
+	HUB6(1,1),
+	HUB6(1,2),
+	HUB6(1,3),
+	HUB6(1,4),
+	HUB6(1,5),
+	{ },
+};
+
+static struct platform_device hub6_device = {
+	.name			= "serial8250",
+	.id			= 4,
+	.dev			= {
+		.platform_data	= hub6_data,
+	},
+};
+
+static int __init hub6_init(void)
+{
+	return platform_device_register(&hub6_device);
+}
+
+module_init(hub6_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c
new file mode 100644
index 0000000..f0c40d6
--- /dev/null
+++ b/drivers/serial/8250_mca.c
@@ -0,0 +1,64 @@
+/*
+ *  linux/drivers/serial/8250_mca.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <linux/serial_8250.h>
+
+/*
+ * FIXME: Should we be doing AUTO_IRQ here?
+ */
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
+#define MCA_FLAGS	UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
+#else
+#define MCA_FLAGS	UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
+#endif
+
+#define PORT(_base,_irq)			\
+	{					\
+		.iobase		= _base,	\
+		.irq		= _irq,		\
+		.uartclk	= 1843200,	\
+		.iotype		= UPIO_PORT,	\
+		.flags		= MCA_FLAGS,	\
+	}
+
+static struct plat_serial8250_port mca_data[] = {
+	PORT(0x3220, 3),
+	PORT(0x3228, 3),
+	PORT(0x4220, 3),
+	PORT(0x4228, 3),
+	PORT(0x5220, 3),
+	PORT(0x5228, 3),
+	{ },
+};
+
+static struct platform_device mca_device = {
+	.name			= "serial8250",
+	.id			= 5,
+	.dev			= {
+		.platform_data	= mca_data,
+	},
+};
+
+static int __init mca_init(void)
+{
+	if (!MCA_bus)
+		return -ENODEV;
+	return platform_device_register(&mca_device);
+}
+
+module_init(mca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 25fcef2..e879bce 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -89,11 +89,11 @@
 	int "Maximum number of non-legacy 8250/16550 serial ports"
 	depends on SERIAL_8250
 	default "4"
-	---help---
-	  Set this to the number of non-legacy serial ports you want
-	  the driver to support.  This includes any ports discovered
-	  via ACPI or PCI enumeration and any ports that may be added
-	  at run-time via hot-plug.
+	help
+	  Set this to the number of serial ports you want the driver
+	  to support.  This includes any ports discovered via ACPI or
+	  PCI enumeration and any ports that may be added at run-time
+	  via hot-plug, or any ISA multi-port serial cards.
 
 config SERIAL_8250_EXTENDED
 	bool "Extended 8250/16550 serial driver options"
@@ -141,31 +141,74 @@
 
 	  If unsure, say N.
 
-config SERIAL_8250_MULTIPORT
-	bool "Support special multiport boards"
-	depends on SERIAL_8250_EXTENDED
-	help
-	  Some multiport serial ports have special ports which are used to
-	  signal when there are any serial ports on the board which need
-	  servicing. Say Y here to enable the serial driver to take advantage
-	  of those special I/O ports.
-
 config SERIAL_8250_RSA
 	bool "Support RSA serial ports"
 	depends on SERIAL_8250_EXTENDED
 	help
 	  ::: To be written :::
 
-comment "Non-8250 serial port support"
+#
+# Multi-port serial cards
+#
+
+config SERIAL_8250_FOURPORT
+	tristate "Support Fourport cards"
+	depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+	help
+	  Say Y here if you have an AST FourPort serial board.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8250_fourport.
+
+config SERIAL_8250_ACCENT
+	tristate "Support Accent cards"
+	depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+	help
+	  Say Y here if you have an Accent Async serial board.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8250_accent.
+
+
+config SERIAL_8250_BOCA
+	tristate "Support Boca cards"
+	depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+	help
+	  Say Y here if you have a Boca serial board.  Please read the Boca
+	  mini-HOWTO, avaialble from <http://www.tldp.org/docs.html#howto>
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8250_boca.
+
+
+config SERIAL_8250_HUB6
+	tristate "Support Hub6 cards"
+	depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+	help
+	  Say Y here if you have a HUB6 serial board.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8250_hub6.
+
+config SERIAL_8250_MCA
+	tristate "Support 8250-type ports on MCA buses"
+	depends on SERIAL_8250 != n && MCA
+	help
+	  Say Y here if you have a MCA serial ports.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8250_mca.
 
 config SERIAL_8250_ACORN
 	tristate "Acorn expansion card serial port support"
-	depends on ARM && ARCH_ACORN && SERIAL_8250
+	depends on ARCH_ACORN && SERIAL_8250
 	help
 	  If you have an Atomwide Serial card or Serial Port card for an Acorn
 	  system, say Y to this option.  The driver can handle 1, 2, or 3 port
 	  cards.  If unsure, say N.
 
+comment "Non-8250 serial port support"
+
 config SERIAL_AMBA_PL010
 	tristate "ARM AMBA PL010 serial port support"
 	depends on ARM_AMBA
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 8f1cdde..65bd438 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -17,6 +17,11 @@
 obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
 obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
 obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
+obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
+obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
+obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
+obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
+obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
 obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
 obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
 obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c149c06..d79cd21 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -32,6 +32,7 @@
 obj-$(CONFIG_USB_MTOUCH)	+= input/
 obj-$(CONFIG_USB_POWERMATE)	+= input/
 obj-$(CONFIG_USB_WACOM)		+= input/
+obj-$(CONFIG_USB_ACECAD)	+= input/
 obj-$(CONFIG_USB_XPAD)		+= input/
 
 obj-$(CONFIG_USB_DABUSB)	+= media/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 57fd07d..eede6be 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -14,14 +14,11 @@
  * This file is licenced under the GPL.
  */
  
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/pci-bridge.h>
 #include <asm/prom.h>
-#ifndef CONFIG_PM
-#	define CONFIG_PM
-#endif
 #endif
 
 #ifndef CONFIG_PCI
@@ -132,7 +129,7 @@
 	/* let things settle down a bit */
 	msleep (100);
 	
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
 	if (_machine == _MACH_Pmac) {
 	   	struct device_node	*of_node;
  
@@ -141,7 +138,7 @@
 		if (of_node)
 			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
 	}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC_PMAC */
 	return 0;
 }
 
@@ -151,7 +148,7 @@
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	int			retval = 0;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
 	if (_machine == _MACH_Pmac) {
 		struct device_node *of_node;
 
@@ -160,7 +157,7 @@
 		if (of_node)
 			pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
 	}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC_PMAC */
 
 	/* resume root hub */
 	if (time_before (jiffies, ohci->next_statechange))
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index d28e7ea..fd59f6b 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -151,6 +151,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called wacom.
 
+config USB_ACECAD
+	tristate "Acecad Flair tablet support"
+	depends on USB && INPUT
+	help
+	  Say Y here if you want to use the USB version of the Acecad Flair
+	  tablet.  Make sure to say Y to "Mouse support"
+	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+	  (CONFIG_INPUT_EVDEV) as well.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called acecad.
+
 config USB_KBTAB
 	tristate "KB Gear JamStudio tablet support"
 	depends on USB && INPUT
@@ -190,6 +202,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called mtouchusb.
 
+config USB_ITMTOUCH
+	tristate "ITM Touch USB Touchscreen Driver"
+	depends on USB && INPUT
+	---help---
+	  Say Y here if you want to use a ITM Touch USB
+	  Touchscreen controller.
+
+	  This touchscreen is used in LG 1510SF monitors.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called itmtouch.
+
 config USB_EGALAX
 	tristate "eGalax TouchKit USB Touchscreen Driver"
 	depends on USB && INPUT
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index 6bcedd1..831b2b0 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -33,7 +33,9 @@
 obj-$(CONFIG_USB_KBTAB)		+= kbtab.o
 obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
 obj-$(CONFIG_USB_MTOUCH)	+= mtouchusb.o
+obj-$(CONFIG_USB_ITMTOUCH)	+= itmtouch.o
 obj-$(CONFIG_USB_EGALAX)	+= touchkitusb.o
 obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
+obj-$(CONFIG_USB_ACECAD)	+= acecad.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.o
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
new file mode 100644
index 0000000..ebcf7c9
--- /dev/null
+++ b/drivers/usb/input/acecad.c
@@ -0,0 +1,285 @@
+/*
+ *  Copyright (c) 2001-2005 Edouard TISSERANT   <edouard.tisserant@wanadoo.fr>
+ *  Copyright (c) 2004-2005 Stephane VOLTZ      <svoltz@numericable.fr>
+ *
+ *  USB Acecad "Acecad Flair" tablet support
+ *
+ *  Changelog:
+ *      v3.2 - Added sysfs support
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v3.2"
+#define DRIVER_DESC    "USB Acecad Flair tablet driver"
+#define DRIVER_LICENSE "GPL"
+#define DRIVER_AUTHOR  "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_ACECAD	0x0460
+#define USB_DEVICE_ID_FLAIR	0x0004
+#define USB_DEVICE_ID_302	0x0008
+
+struct usb_acecad {
+	char name[128];
+	char phys[64];
+	struct usb_device *usbdev;
+	struct input_dev dev;
+	struct urb *irq;
+
+	signed char *data;
+	dma_addr_t data_dma;
+};
+
+static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_acecad *acecad = urb->context;
+	unsigned char *data = acecad->data;
+	struct input_dev *dev = &acecad->dev;
+	int prox, status;
+
+	switch (urb->status) {
+		case 0:
+			/* success */
+			break;
+		case -ECONNRESET:
+		case -ENOENT:
+		case -ESHUTDOWN:
+			/* this urb is terminated, clean up */
+			dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+			return;
+		default:
+			dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+			goto resubmit;
+	}
+
+	prox = (data[0] & 0x04) >> 2;
+	input_report_key(dev, BTN_TOOL_PEN, prox);
+
+	if (prox) {
+		int x = data[1] | (data[2] << 8);
+		int y = data[3] | (data[4] << 8);
+		/*Pressure should compute the same way for flair and 302*/
+		int pressure = data[5] | ((int)data[6] << 8);
+		int touch = data[0] & 0x01;
+		int stylus = (data[0] & 0x10) >> 4;
+		int stylus2 = (data[0] & 0x20) >> 5;
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
+		input_report_abs(dev, ABS_PRESSURE, pressure);
+		input_report_key(dev, BTN_TOUCH, touch);
+		input_report_key(dev, BTN_STYLUS, stylus);
+		input_report_key(dev, BTN_STYLUS2, stylus2);
+	}
+
+	/* event termination */
+	input_sync(dev);
+
+resubmit:
+	status = usb_submit_urb (urb, GFP_ATOMIC);
+	if (status)
+		err ("can't resubmit intr, %s-%s/input0, status %d",
+			acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
+}
+
+static int usb_acecad_open(struct input_dev *dev)
+{
+	struct usb_acecad *acecad = dev->private;
+
+	acecad->irq->dev = acecad->usbdev;
+	if (usb_submit_urb(acecad->irq, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void usb_acecad_close(struct input_dev *dev)
+{
+	struct usb_acecad *acecad = dev->private;
+
+	usb_kill_urb(acecad->irq);
+}
+
+static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_host_interface *interface = intf->cur_altsetting;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_acecad *acecad;
+	int pipe, maxp;
+	char path[64];
+
+	if (interface->desc.bNumEndpoints != 1)
+		return -ENODEV;
+
+	endpoint = &interface->endpoint[0].desc;
+
+	if (!(endpoint->bEndpointAddress & 0x80))
+		return -ENODEV;
+
+	if ((endpoint->bmAttributes & 3) != 3)
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL);
+	if (!acecad)
+		return -ENOMEM;
+
+	acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma);
+	if (!acecad->data)
+		goto fail1;
+
+	acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!acecad->irq)
+		goto fail2;
+
+	if (dev->manufacturer)
+		strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name));
+
+	if (dev->product) {
+		if (dev->manufacturer)
+			strlcat(acecad->name, " ", sizeof(acecad->name));
+		strlcat(acecad->name, dev->product, sizeof(acecad->name));
+	}
+
+	usb_make_path(dev, path, sizeof(path));
+	snprintf(acecad->phys, sizeof(acecad->phys), "%s/input0", path);
+
+	acecad->usbdev = dev;
+
+	acecad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	acecad->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+	acecad->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+	acecad->dev.keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+
+	switch (id->driver_info) {
+		case 0:
+			acecad->dev.absmax[ABS_X] = 5000;
+			acecad->dev.absmax[ABS_Y] = 3750;
+			acecad->dev.absmax[ABS_PRESSURE] = 512;
+			if (!strlen(acecad->name))
+				snprintf(acecad->name, sizeof(acecad->name),
+					"USB Acecad Flair Tablet %04x:%04x",
+					dev->descriptor.idVendor, dev->descriptor.idProduct);
+			break;
+		case 1:
+			acecad->dev.absmax[ABS_X] = 3000;
+			acecad->dev.absmax[ABS_Y] = 2250;
+			acecad->dev.absmax[ABS_PRESSURE] = 1024;
+			if (!strlen(acecad->name))
+				snprintf(acecad->name, sizeof(acecad->name),
+					"USB Acecad 302 Tablet %04x:%04x",
+					dev->descriptor.idVendor, dev->descriptor.idProduct);
+			break;
+	}
+
+	acecad->dev.absfuzz[ABS_X] = 4;
+	acecad->dev.absfuzz[ABS_Y] = 4;
+
+	acecad->dev.private = acecad;
+	acecad->dev.open = usb_acecad_open;
+	acecad->dev.close = usb_acecad_close;
+
+	acecad->dev.name = acecad->name;
+	acecad->dev.phys = acecad->phys;
+	acecad->dev.id.bustype = BUS_USB;
+	acecad->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
+	acecad->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
+	acecad->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+	acecad->dev.dev = &intf->dev;
+
+	usb_fill_int_urb(acecad->irq, dev, pipe,
+			acecad->data, maxp > 8 ? 8 : maxp,
+			usb_acecad_irq, acecad, endpoint->bInterval);
+	acecad->irq->transfer_dma = acecad->data_dma;
+	acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	input_register_device(&acecad->dev);
+
+	printk(KERN_INFO "input: %s with packet size %d on %s\n",
+		acecad->name, maxp, path);
+
+	usb_set_intfdata(intf, acecad);
+
+	return 0;
+
+ fail2:	usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
+ fail1:	kfree(acecad);
+	return -ENOMEM;
+}
+
+static void usb_acecad_disconnect(struct usb_interface *intf)
+{
+	struct usb_acecad *acecad = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (acecad) {
+		usb_kill_urb(acecad->irq);
+		input_unregister_device(&acecad->dev);
+		usb_free_urb(acecad->irq);
+		usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
+		kfree(acecad);
+	}
+}
+
+static struct usb_device_id usb_acecad_id_table [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 },
+	{ USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302),	 .driver_info = 1 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
+
+static struct usb_driver usb_acecad_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"usb_acecad",
+	.probe =	usb_acecad_probe,
+	.disconnect =	usb_acecad_disconnect,
+	.id_table =	usb_acecad_id_table,
+};
+
+static int __init usb_acecad_init(void)
+{
+	int result = usb_register(&usb_acecad_driver);
+	if (result == 0)
+		info(DRIVER_VERSION ":" DRIVER_DESC);
+	return result;
+}
+
+static void __exit usb_acecad_exit(void)
+{
+	usb_deregister(&usb_acecad_driver);
+}
+
+module_init(usb_acecad_init);
+module_exit(usb_acecad_exit);
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index e991f7e..6bb0f25 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -1,7 +1,7 @@
 /*
  *  Native support for the Aiptek HyperPen USB Tablets
  *  (4000U/5000U/6000U/8000U/12000U)
- *  
+ *
  *  Copyright (c) 2001      Chris Atenasio   <chris@crud.net>
  *  Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net>
  *
@@ -31,7 +31,7 @@
  *           - Added support for the sysfs interface, deprecating the
  *             procfs interface for 2.5.x kernel. Also added support for
  *             Wheel command. Bryan W. Headley July-15-2003.
- *      v1.2 - Reworked jitter timer as a kernel thread. 
+ *      v1.2 - Reworked jitter timer as a kernel thread.
  *             Bryan W. Headley November-28-2003/Jan-10-2004.
  *      v1.3 - Repaired issue of kernel thread going nuts on single-processor
  *             machines, introduced programmableDelay as a command line
@@ -49,10 +49,10 @@
  * NOTE:
  *      This kernel driver is augmented by the "Aiptek" XFree86 input
  *      driver for your X server, as well as the Gaiptek GUI Front-end
- *      "Tablet Manager". 
- *      These three products are highly interactive with one another, 
+ *      "Tablet Manager".
+ *      These three products are highly interactive with one another,
  *      so therefore it's easier to document them all as one subsystem.
- *      Please visit the project's "home page", located at, 
+ *      Please visit the project's "home page", located at,
  *      http://aiptektablet.sourceforge.net.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -156,7 +156,7 @@
  * Command/Data    Description     Return Bytes    Return Value
  * 0x10/0x00       SwitchToMouse       0
  * 0x10/0x01       SwitchToTablet      0
- * 0x18/0x04       SetResolution       0 
+ * 0x18/0x04       SetResolution       0
  * 0x12/0xFF       AutoGainOn          0
  * 0x17/0x00       FilterOn            0
  * 0x01/0x00       GetXExtension       2           MaxX
@@ -247,7 +247,7 @@
 #define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE	2
 #define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED		3
 
-	/* Time to wait (in ms) to help mask hand jittering 
+	/* Time to wait (in ms) to help mask hand jittering
 	 * when pressing the stylus buttons.
 	 */
 #define AIPTEK_JITTER_DELAY_DEFAULT			50
@@ -324,7 +324,6 @@
 	struct aiptek_settings curSetting;	/* tablet's current programmable */
 	struct aiptek_settings newSetting;	/* ... and new param settings    */
 	unsigned int ifnum;			/* interface number for IO       */
-	int openCount;				/* module use counter            */
 	int diagnostic;				/* tablet diagnostic codes       */
 	unsigned long eventCount;		/* event count                   */
 	int inDelay;				/* jitter: in jitter delay?      */
@@ -791,7 +790,7 @@
  * specific Aiptek model numbers, because there has been overlaps,
  * use, and reuse of id's in existing models. Certain models have
  * been known to use more than one ID, indicative perhaps of
- * manufacturing revisions. In any event, we consider these 
+ * manufacturing revisions. In any event, we consider these
  * IDs to not be model-specific nor unique.
  */
 static const struct usb_device_id aiptek_ids[] = {
@@ -814,15 +813,9 @@
 {
 	struct aiptek *aiptek = inputdev->private;
 
-	if (aiptek->openCount++ > 0) {
-		return 0;
-	}
-
 	aiptek->urb->dev = aiptek->usbdev;
-	if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) {
-		aiptek->openCount--;
+	if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
 		return -EIO;
-	}
 
 	return 0;
 }
@@ -834,13 +827,11 @@
 {
 	struct aiptek *aiptek = inputdev->private;
 
-	if (--aiptek->openCount == 0) {
-		usb_kill_urb(aiptek->urb);
-	}
+	usb_kill_urb(aiptek->urb);
 }
 
 /***********************************************************************
- * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x, 
+ * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
  * where they were known as usb_set_report and usb_get_report.
  */
 static int
@@ -2252,7 +2243,6 @@
 				AIPTEK_PACKET_LENGTH,
 				aiptek->data, aiptek->data_dma);
 		kfree(aiptek);
-		aiptek = NULL;
 	}
 }
 
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index 7d30f55..654ac45 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -1,15 +1,15 @@
-/* 
+/*
  *  USB ATI Remote support
  *
  *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
  *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
  *
  *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
- *  porting to the 2.6 kernel interfaces, along with other modification 
+ *  porting to the 2.6 kernel interfaces, along with other modification
  *  to better match the style of the existing usb/input drivers.  However, the
  *  protocol and hardware handling is essentially unchanged from 2.1.1.
- *  
- *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by 
+ *
+ *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
  *  Vojtech Pavlik.
  *
  *  Changes:
@@ -23,64 +23,64 @@
  *            Added support for the "Lola" remote contributed by:
  *                Seth Cohn <sethcohn@yahoo.com>
  *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *
  * Hardware & software notes
  *
- * These remote controls are distributed by ATI as part of their 
- * "All-In-Wonder" video card packages.  The receiver self-identifies as a 
+ * These remote controls are distributed by ATI as part of their
+ * "All-In-Wonder" video card packages.  The receiver self-identifies as a
  * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
  *
- * The "Lola" remote is available from X10.  See: 
+ * The "Lola" remote is available from X10.  See:
  *    http://www.x10.com/products/lola_sg1.htm
  * The Lola is similar to the ATI remote but has no mouse support, and slightly
  * different keys.
  *
- * It is possible to use multiple receivers and remotes on multiple computers 
+ * It is possible to use multiple receivers and remotes on multiple computers
  * simultaneously by configuring them to use specific channels.
- * 
- * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.  
- * Actually, it may even support more, at least in some revisions of the 
+ *
+ * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
+ * Actually, it may even support more, at least in some revisions of the
  * hardware.
  *
  * Each remote can be configured to transmit on one channel as follows:
- *   - Press and hold the "hand icon" button.  
- *   - When the red LED starts to blink, let go of the "hand icon" button. 
- *   - When it stops blinking, input the channel code as two digits, from 01 
+ *   - Press and hold the "hand icon" button.
+ *   - When the red LED starts to blink, let go of the "hand icon" button.
+ *   - When it stops blinking, input the channel code as two digits, from 01
  *     to 16, and press the hand icon again.
- * 
+ *
  * The timing can be a little tricky.  Try loading the module with debug=1
  * to have the kernel print out messages about the remote control number
  * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
  *
  * The driver has a "channel_mask" parameter. This bitmask specifies which
- * channels will be ignored by the module.  To mask out channels, just add 
+ * channels will be ignored by the module.  To mask out channels, just add
  * all the 2^channel_number values together.
  *
  * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
- * ignore signals coming from remote controls transmitting on channel 4, but 
+ * ignore signals coming from remote controls transmitting on channel 4, but
  * accept all other channels.
  *
- * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be 
+ * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
  * ignored.
  *
- * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this 
+ * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
  * parameter are unused.
  *
  */
@@ -99,13 +99,13 @@
 /*
  * Module and Version Information, Module Parameters
  */
- 
-#define ATI_REMOTE_VENDOR_ID 	0x0bc7
-#define ATI_REMOTE_PRODUCT_ID 	0x004
-#define LOLA_REMOTE_PRODUCT_ID 	0x002
+
+#define ATI_REMOTE_VENDOR_ID	0x0bc7
+#define ATI_REMOTE_PRODUCT_ID	0x004
+#define LOLA_REMOTE_PRODUCT_ID	0x002
 #define MEDION_REMOTE_PRODUCT_ID 0x006
 
-#define DRIVER_VERSION 	        "2.2.1"
+#define DRIVER_VERSION	        "2.2.1"
 #define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
 #define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
 
@@ -113,18 +113,18 @@
 #define DATA_BUFSIZE      63    /* size of URB data buffers */
 #define ATI_INPUTNUM      1     /* Which input device to register as */
 
-static unsigned long channel_mask = 0;
+static unsigned long channel_mask;
 module_param(channel_mask, ulong, 0444);
 MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
 
 #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
 #undef err
 #define err(format, arg...) printk(KERN_ERR format , ## arg)
- 
+
 static struct usb_device_id ati_remote_table[] = {
 	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
 	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
@@ -148,7 +148,7 @@
 /* Acceleration curve for directional control pad */
 static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
 
-/* Duplicate event filtering time. 
+/* Duplicate event filtering time.
  * Sequential, identical KIND_FILTERED inputs with less than
  * FILTER_TIME jiffies between them are considered as repeat
  * events. The hardware generates 5 events for the first keypress
@@ -161,10 +161,10 @@
 static DECLARE_MUTEX(disconnect_sem);
 
 struct ati_remote {
-	struct input_dev idev;		
+	struct input_dev idev;
 	struct usb_device *udev;
 	struct usb_interface *interface;
-		
+
 	struct urb *irq_urb;
 	struct urb *out_urb;
 	struct usb_endpoint_descriptor *endpoint_in;
@@ -174,13 +174,11 @@
 	dma_addr_t inbuf_dma;
 	dma_addr_t outbuf_dma;
 
-	int open;                   /* open counter */
-	
 	unsigned char old_data[2];  /* Detect duplicate events */
 	unsigned long old_jiffies;
 	unsigned long acc_jiffies;  /* handle acceleration */
 	unsigned int repeat_count;
-	
+
 	char name[NAME_BUFSIZE];
 	char phys[NAME_BUFSIZE];
 
@@ -206,14 +204,14 @@
 	int type;
 	unsigned int code;
 	int value;
-}  ati_remote_tbl[] = 
+}  ati_remote_tbl[] =
 {
 	/* Directional control pad axes */
 	{KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},	 /* left */
 	{KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
 	{KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},	 /* up */
 	{KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
-	/* Directional control pad diagonals */	
+	/* Directional control pad diagonals */
 	{KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
 	{KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
 	{KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
@@ -225,7 +223,7 @@
 	{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
 	{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
 
-	/* Artificial "doubleclick" events are generated by the hardware. 
+	/* Artificial "doubleclick" events are generated by the hardware.
 	 * They are mapped to the "side" and "extra" mouse buttons here. */
 	{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
 	{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
@@ -273,15 +271,15 @@
 	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
 	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
 	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
-	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */ 
+	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
 	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
 	{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
 	{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
 	{KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
 	{KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
 	{KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
-	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */	
-	
+	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
+
 	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
 };
 
@@ -315,7 +313,7 @@
 	if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
 		warn("Weird byte 0x%02x", data[0]);
 	else if (len == 4)
-		warn("Weird key %02x %02x %02x %02x", 
+		warn("Weird key %02x %02x %02x %02x",
 		     data[0], data[1], data[2], data[3]);
 	else
 		warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
@@ -328,25 +326,16 @@
 static int ati_remote_open(struct input_dev *inputdev)
 {
 	struct ati_remote *ati_remote = inputdev->private;
-	int retval = 0;
-
-	down(&disconnect_sem);
-
-	if (ati_remote->open++)
-		goto exit;
 
 	/* On first open, submit the read urb which was set up previously. */
 	ati_remote->irq_urb->dev = ati_remote->udev;
 	if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
-		dev_err(&ati_remote->interface->dev, 
+		dev_err(&ati_remote->interface->dev,
 			"%s: usb_submit_urb failed!\n", __FUNCTION__);
-		ati_remote->open--;
-		retval = -EIO;
+		return -EIO;
 	}
 
-exit:
-	up(&disconnect_sem);
-	return retval;
+	return 0;
 }
 
 /*
@@ -355,9 +344,8 @@
 static void ati_remote_close(struct input_dev *inputdev)
 {
 	struct ati_remote *ati_remote = inputdev->private;
-	
-	if (!--ati_remote->open)
-		usb_kill_urb(ati_remote->irq_urb);
+
+	usb_kill_urb(ati_remote->irq_urb);
 }
 
 /*
@@ -366,13 +354,13 @@
 static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
 {
 	struct ati_remote *ati_remote = urb->context;
-	
+
 	if (urb->status) {
 		dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
 			__FUNCTION__, urb->status);
 		return;
 	}
-	
+
 	ati_remote->send_flags |= SEND_FLAG_COMPLETE;
 	wmb();
 	wake_up(&ati_remote->wait);
@@ -380,16 +368,16 @@
 
 /*
  *	ati_remote_sendpacket
- *		
+ *
  *	Used to send device initialization strings
  */
 static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
 {
 	int retval = 0;
-	
+
 	/* Set up out_urb */
 	memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
-	((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);	
+	((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
 
 	ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
 	ati_remote->out_urb->dev = ati_remote->udev;
@@ -397,17 +385,17 @@
 
 	retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
 	if (retval) {
-		dev_dbg(&ati_remote->interface->dev, 
+		dev_dbg(&ati_remote->interface->dev,
 			 "sendpacket: usb_submit_urb failed: %d\n", retval);
 		return retval;
 	}
 
 	wait_event_timeout(ati_remote->wait,
 		((ati_remote->out_urb->status != -EINPROGRESS) ||
-		 	(ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+			(ati_remote->send_flags & SEND_FLAG_COMPLETE)),
 		HZ);
 	usb_kill_urb(ati_remote->out_urb);
-	
+
 	return retval;
 }
 
@@ -419,15 +407,15 @@
 	int i;
 
 	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
-		/* 
-		 * Decide if the table entry matches the remote input. 
+		/*
+		 * Decide if the table entry matches the remote input.
 		 */
 		if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
-		    ((((ati_remote_tbl[i].data1 >> 4) - 
-		       (d1 >> 4) + rem) & 0x0f) == 0x0f) && 
+		    ((((ati_remote_tbl[i].data1 >> 4) -
+		       (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
 		    (ati_remote_tbl[i].data2 == d2))
 			return i;
-		
+
 	}
 	return -1;
 }
@@ -435,16 +423,16 @@
 /*
  *	ati_remote_report_input
  */
-static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)	
+static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
 {
 	struct ati_remote *ati_remote = urb->context;
 	unsigned char *data= ati_remote->inbuf;
-	struct input_dev *dev = &ati_remote->idev; 
+	struct input_dev *dev = &ati_remote->idev;
 	int index, acc;
 	int remote_num;
-	
+
 	/* Deal with strange looking inputs */
-	if ( (urb->actual_length != 4) || (data[0] != 0x14) || 
+	if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
 		((data[3] & 0x0f) != 0x00) ) {
 		ati_remote_dump(data, urb->actual_length);
 		return;
@@ -453,7 +441,7 @@
 	/* Mask unwanted remote channels.  */
 	/* note: remote_num is 0-based, channel 1 on remote == 0 here */
 	remote_num = (data[3] >> 4) & 0x0f;
-        if (channel_mask & (1 << (remote_num + 1))) { 
+        if (channel_mask & (1 << (remote_num + 1))) {
 		dbginfo(&ati_remote->interface->dev,
 			"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
 			remote_num, data[1], data[2], channel_mask);
@@ -463,37 +451,36 @@
 	/* Look up event code index in translation table */
 	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
 	if (index < 0) {
-		dev_warn(&ati_remote->interface->dev, 
-			 "Unknown input from channel 0x%02x: data %02x,%02x\n", 
+		dev_warn(&ati_remote->interface->dev,
+			 "Unknown input from channel 0x%02x: data %02x,%02x\n",
 			 remote_num, data[1], data[2]);
 		return;
-	} 
-	dbginfo(&ati_remote->interface->dev, 
+	}
+	dbginfo(&ati_remote->interface->dev,
 		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
 		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
-	
+
 	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
 		input_regs(dev, regs);
 		input_event(dev, ati_remote_tbl[index].type,
 			ati_remote_tbl[index].code,
 			ati_remote_tbl[index].value);
 		input_sync(dev);
-		
+
 		ati_remote->old_jiffies = jiffies;
 		return;
 	}
-	
+
 	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
 		/* Filter duplicate events which happen "too close" together. */
-		if ((ati_remote->old_data[0] == data[1]) && 
-	 		(ati_remote->old_data[1] == data[2]) && 
-	 		((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
+		if ((ati_remote->old_data[0] == data[1]) &&
+			(ati_remote->old_data[1] == data[2]) &&
+			((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
 			ati_remote->repeat_count++;
-		} 
-		else {
+		} else {
 			ati_remote->repeat_count = 0;
 		}
-		
+
 		ati_remote->old_data[0] = data[1];
 		ati_remote->old_data[1] = data[2];
 		ati_remote->old_jiffies = jiffies;
@@ -501,7 +488,7 @@
 		if ((ati_remote->repeat_count > 0)
 		    && (ati_remote->repeat_count < 5))
 			return;
-		
+
 
 		input_regs(dev, regs);
 		input_event(dev, ati_remote_tbl[index].type,
@@ -511,13 +498,13 @@
 		input_sync(dev);
 
 		return;
-	}			
-	
-	/* 
+	}
+
+	/*
 	 * Other event kinds are from the directional control pad, and have an
 	 * acceleration factor applied to them.  Without this acceleration, the
 	 * control pad is mostly unusable.
-	 * 
+	 *
 	 * If elapsed time since last event is > 1/4 second, user "stopped",
 	 * so reset acceleration. Otherwise, user is probably holding the control
 	 * pad down, so we increase acceleration, ramping up over two seconds to
@@ -559,7 +546,7 @@
 		input_report_rel(dev, REL_Y, acc);
 		break;
 	default:
-		dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", 
+		dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
 			ati_remote_tbl[index].kind);
 	}
 	input_sync(dev);
@@ -586,12 +573,12 @@
 	case -ESHUTDOWN:
 		dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
 			__FUNCTION__);
-		return;	
+		return;
 	default:		/* error */
-		dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", 
+		dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
 			__FUNCTION__, urb->status);
 	}
-	
+
 	retval = usb_submit_urb(urb, SLAB_ATOMIC);
 	if (retval)
 		dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
@@ -603,8 +590,6 @@
  */
 static void ati_remote_delete(struct ati_remote *ati_remote)
 {
-	if (!ati_remote) return;
-
 	if (ati_remote->irq_urb)
 		usb_kill_urb(ati_remote->irq_urb);
 
@@ -614,16 +599,16 @@
 	input_unregister_device(&ati_remote->idev);
 
 	if (ati_remote->inbuf)
-		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
+		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
 				ati_remote->inbuf, ati_remote->inbuf_dma);
-		
+
 	if (ati_remote->outbuf)
-		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
+		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
 				ati_remote->outbuf, ati_remote->outbuf_dma);
-	
+
 	if (ati_remote->irq_urb)
 		usb_free_urb(ati_remote->irq_urb);
-	
+
 	if (ati_remote->out_urb)
 		usb_free_urb(ati_remote->out_urb);
 
@@ -636,21 +621,21 @@
 	int i;
 
 	idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-	idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | 
+	idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
 					  BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
 	idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
 	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
 		if (ati_remote_tbl[i].type == EV_KEY)
 			set_bit(ati_remote_tbl[i].code, idev->keybit);
-	
+
 	idev->private = ati_remote;
 	idev->open = ati_remote_open;
 	idev->close = ati_remote_close;
-	
+
 	idev->name = ati_remote->name;
 	idev->phys = ati_remote->phys;
-	
-	idev->id.bustype = BUS_USB;		
+
+	idev->id.bustype = BUS_USB;
 	idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor);
 	idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct);
 	idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice);
@@ -661,27 +646,27 @@
 {
 	struct usb_device *udev = ati_remote->udev;
 	int pipe, maxp;
-		
+
 	init_waitqueue_head(&ati_remote->wait);
 
 	/* Set up irq_urb */
 	pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
 	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-	
-	usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, 
-			 maxp, ati_remote_irq_in, ati_remote, 
+
+	usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
+			 maxp, ati_remote_irq_in, ati_remote,
 			 ati_remote->endpoint_in->bInterval);
 	ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
 	ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-	
+
 	/* Set up out_urb */
 	pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
 	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
 
-	usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, 
-			 maxp, ati_remote_irq_out, ati_remote, 
+	usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
+			 maxp, ati_remote_irq_out, ati_remote,
 			 ati_remote->endpoint_out->bInterval);
 	ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
 	ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -689,11 +674,11 @@
 	/* send initialization strings */
 	if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
 	    (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
-		dev_err(&ati_remote->interface->dev, 
+		dev_err(&ati_remote->interface->dev,
 			 "Initializing ati_remote hardware failed.\n");
 		return 1;
 	}
-	
+
 	return 0;
 }
 
@@ -770,7 +755,7 @@
 
 	if (!strlen(ati_remote->name))
 		sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)",
-			le16_to_cpu(ati_remote->udev->descriptor.idVendor), 
+			le16_to_cpu(ati_remote->udev->descriptor.idVendor),
 			le16_to_cpu(ati_remote->udev->descriptor.idProduct));
 
 	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
@@ -782,11 +767,11 @@
 	ati_remote_input_init(ati_remote);
 	input_register_device(&ati_remote->idev);
 
-	dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", 
+	dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n",
 		 ati_remote->name, path);
 
 	usb_set_intfdata(interface, ati_remote);
-	
+
 error:
 	if (retval)
 		ati_remote_delete(ati_remote);
@@ -801,18 +786,14 @@
 {
 	struct ati_remote *ati_remote;
 
-	down(&disconnect_sem);
-
 	ati_remote = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 	if (!ati_remote) {
 		warn("%s - null device?\n", __FUNCTION__);
 		return;
 	}
-	
-	ati_remote_delete(ati_remote);
 
-	up(&disconnect_sem);
+	ati_remote_delete(ati_remote);
 }
 
 /*
@@ -821,7 +802,7 @@
 static int __init ati_remote_init(void)
 {
 	int result;
-	
+
 	result = usb_register(&ati_remote_driver);
 	if (result)
 		err("usb_register error #%d\n", result);
@@ -839,8 +820,8 @@
 	usb_deregister(&ati_remote_driver);
 }
 
-/* 
- *	module specification 
+/*
+ *	module specification
  */
 
 module_init(ati_remote_init);
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 740dec1..100b49bd 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -232,7 +232,7 @@
 	report->size += parser->global.report_size * parser->global.report_count;
 
 	if (!parser->local.usage_index) /* Ignore padding fields */
-		return 0; 
+		return 0;
 
 	usages = max_t(int, parser->local.usage_index, parser->global.report_count);
 
@@ -765,7 +765,7 @@
 static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
 {
 	report += (offset >> 5) << 2; offset &= 31;
-	return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1 << n) - 1);
+	return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1);
 }
 
 static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
@@ -1233,6 +1233,13 @@
 	return 0;
 }
 
+static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
+		ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
 static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 		unsigned char type, void *buf, int size)
 {
@@ -1301,10 +1308,6 @@
 
 	if (err)
 		warn("timeout initializing reports\n");
-
-	usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
-		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
-		hid->ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
 }
 
 #define USB_VENDOR_ID_WACOM		0x056a
@@ -1318,6 +1321,10 @@
 #define USB_DEVICE_ID_WACOM_INTUOS3	0x00B0
 #define USB_DEVICE_ID_WACOM_CINTIQ	0x003F
 
+#define USB_VENDOR_ID_ACECAD		0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR	0x0004
+#define USB_DEVICE_ID_ACECAD_302	0x0008
+
 #define USB_VENDOR_ID_KBGEAR		0x084e
 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
 
@@ -1502,6 +1509,9 @@
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
 
+	{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
+
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
@@ -1590,6 +1600,8 @@
 		return NULL;
 	}
 
+	hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
+
 	if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
 		dbg("reading report descriptor failed");
 		kfree(rdesc);
@@ -1635,7 +1647,7 @@
 		/* Change the polling interval of mice. */
 		if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
 			interval = hid_mousepoll_interval;
-		
+
 		if (endpoint->bEndpointAddress & USB_DIR_IN) {
 			if (hid->urbin)
 				continue;
diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
index 2b91705..52437e5 100644
--- a/drivers/usb/input/hid-debug.h
+++ b/drivers/usb/input/hid-debug.h
@@ -67,7 +67,7 @@
       {0, 0x44, "Vbry"},
       {0, 0x45, "Vbrz"},
       {0, 0x46, "Vno"},
-    {0, 0x80, "SystemControl"}, 
+    {0, 0x80, "SystemControl"},
       {0, 0x81, "SystemPowerDown"},
       {0, 0x82, "SystemSleep"},
       {0, 0x83, "SystemWakeUp"},
@@ -347,7 +347,7 @@
 
 static void hid_dump_field(struct hid_field *field, int n) {
 	int j;
-	
+
 	if (field->physical) {
 		tab(n);
 		printk("Physical(");
@@ -408,7 +408,7 @@
 					printk("%s", units[sys][i]);
 					if(nibble != 1) {
 						/* This is a _signed_ nibble(!) */
-	
+
 						int val = nibble & 0x7;
 						if(nibble & 0x08)
 							val = -((0x7 & ~val) +1);
@@ -443,7 +443,7 @@
 	struct list_head *list;
 	unsigned i,k;
 	static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
-	
+
 	for (i = 0; i < HID_REPORT_TYPES; i++) {
 		report_enum = device->report_enum + i;
 		list = report_enum->report_list.next;
@@ -664,8 +664,8 @@
 static char *relatives[REL_MAX + 1] = {
 	[REL_X] = "X",			[REL_Y] = "Y",
 	[REL_Z] = "Z",			[REL_HWHEEL] = "HWheel",
-	[REL_DIAL] = "Dial",		[REL_WHEEL] = "Wheel", 
-	[REL_MISC] = "Misc",	
+	[REL_DIAL] = "Dial",		[REL_WHEEL] = "Wheel",
+	[REL_MISC] = "Misc",
 };
 
 static char *absolutes[ABS_MAX + 1] = {
@@ -690,9 +690,9 @@
 };
 
 static char *leds[LED_MAX + 1] = {
-	[LED_NUML] = "NumLock",		[LED_CAPSL] = "CapsLock", 
+	[LED_NUML] = "NumLock",		[LED_CAPSL] = "CapsLock",
 	[LED_SCROLLL] = "ScrollLock",	[LED_COMPOSE] = "Compose",
-	[LED_KANA] = "Kana",		[LED_SLEEP] = "Sleep", 
+	[LED_KANA] = "Kana",		[LED_SLEEP] = "Sleep",
 	[LED_SUSPEND] = "Suspend",	[LED_MUTE] = "Mute",
 	[LED_MISC] = "Misc",
 };
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
index 5553c35..9ac1e90 100644
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/usb/input/hid-input.c
@@ -164,7 +164,7 @@
 				case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
 				case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
 				case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
-					if (field->flags & HID_MAIN_ITEM_RELATIVE) 
+					if (field->flags & HID_MAIN_ITEM_RELATIVE)
 						map_rel(usage->hid & 0xf);
 					else
 						map_abs(usage->hid & 0xf);
@@ -297,7 +297,7 @@
 		case HID_UP_MSVENDOR:
 
 			goto ignore;
-			
+
 		case HID_UP_PID:
 
 			set_bit(EV_FF, input->evbit);
@@ -349,7 +349,7 @@
 		goto ignore;
 
 	if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
-		 (usage->type == EV_REL) && (usage->code == REL_WHEEL)) 
+		 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
 			set_bit(REL_HWHEEL, bit);
 
 	if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
@@ -365,11 +365,11 @@
 			a = field->logical_minimum = 0;
 			b = field->logical_maximum = 255;
 		}
-		
+
 		if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
 			input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
 		else	input_set_abs_params(input, usage->code, a, b, 0, 0);
-		
+
 	}
 
 	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
@@ -420,7 +420,7 @@
 		return;
 	}
 
-	if (usage->hat_min < usage->hat_max || usage->hat_dir) { 
+	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
 		int hat_dir = usage->hat_dir;
 		if (!hat_dir)
 			hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
@@ -551,7 +551,7 @@
 	for (i = 0; i < hid->maxcollection; i++)
 		if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
 		    hid->collection[i].type == HID_COLLECTION_PHYSICAL)
-		    	if (IS_INPUT_APPLICATION(hid->collection[i].usage))
+			if (IS_INPUT_APPLICATION(hid->collection[i].usage))
 				break;
 
 	if (i == hid->maxcollection)
@@ -592,7 +592,7 @@
 				for (j = 0; j < report->field[i]->maxusage; j++)
 					hidinput_configure_usage(hidinput, report->field[i],
 								 report->field[i]->usage + j);
-			
+
 			if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
 				/* This will leave hidinput NULL, so that it
 				 * allocates another one if we have more inputs on
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index 0d7404b..0c4c77a 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -94,7 +94,7 @@
 					isn't really necessary */
 
 	unsigned long flags[1];      /* Contains various information about the
-				        state of the driver for this device */	
+				        state of the driver for this device */
 
 	struct timer_list timer;
 };
@@ -234,7 +234,7 @@
 		kfree(ret);
 		return NULL;
 	}
-	memset(ret->field[0]->value, 0, sizeof(s32[8]));	
+	memset(ret->field[0]->value, 0, sizeof(s32[8]));
 
 	return ret;
 }
@@ -295,11 +295,11 @@
 	unsigned long flags;
 
 	if (type != EV_FF)                     return -EINVAL;
-       	if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
+	if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
 	if (value < 0)                         return -EINVAL;
 
 	spin_lock_irqsave(&lgff->lock, flags);
-	
+
 	if (value > 0) {
 		if (test_bit(EFFECT_STARTED, effect->flags)) {
 			spin_unlock_irqrestore(&lgff->lock, flags);
@@ -345,7 +345,7 @@
 		  and perform ioctls on the same fd all at the same time */
 		if ( current->pid == lgff->effects[i].owner
 		     && test_bit(EFFECT_USED, lgff->effects[i].flags)) {
-			
+
 			if (hid_lgff_erase(dev, i))
 				warn("erase effect %d failed", i);
 		}
@@ -378,7 +378,7 @@
 	struct lgff_effect new;
 	int id;
 	unsigned long flags;
-	
+
 	dbg("ioctl rumble");
 
 	if (!test_bit(effect->type, input->ffbit)) return -EINVAL;
@@ -441,7 +441,7 @@
 
 	spin_lock_irqsave(&lgff->lock, flags);
 
- 	for (i=0; i<LGFF_EFFECTS; ++i) {
+	for (i=0; i<LGFF_EFFECTS; ++i) {
 		struct lgff_effect* effect = lgff->effects +i;
 
 		if (test_bit(EFFECT_PLAYING, effect->flags)) {
@@ -491,7 +491,7 @@
 				set_bit(EFFECT_PLAYING, lgff->effects[i].flags);
 			}
 		}
- 	}
+	}
 
 #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
 
@@ -524,5 +524,5 @@
 		add_timer(&lgff->timer);
 	}
 
- 	spin_unlock_irqrestore(&lgff->lock, flags);
+	spin_unlock_irqrestore(&lgff->lock, flags);
 }
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
index 6d9329c..c1b6b69 100644
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -118,7 +118,7 @@
 #define HID_MAIN_ITEM_CONSTANT		0x001
 #define HID_MAIN_ITEM_VARIABLE		0x002
 #define HID_MAIN_ITEM_RELATIVE		0x004
-#define HID_MAIN_ITEM_WRAP		0x008	
+#define HID_MAIN_ITEM_WRAP		0x008
 #define HID_MAIN_ITEM_NONLINEAR		0x010
 #define HID_MAIN_ITEM_NO_PREFERRED	0x020
 #define HID_MAIN_ITEM_NULL_STATE	0x040
@@ -172,14 +172,14 @@
 #define HID_USAGE_PAGE		0xffff0000
 
 #define HID_UP_UNDEFINED	0x00000000
-#define HID_UP_GENDESK 		0x00010000
-#define HID_UP_KEYBOARD 	0x00070000
-#define HID_UP_LED 		0x00080000
-#define HID_UP_BUTTON 		0x00090000
-#define HID_UP_ORDINAL 		0x000a0000
+#define HID_UP_GENDESK		0x00010000
+#define HID_UP_KEYBOARD		0x00070000
+#define HID_UP_LED		0x00080000
+#define HID_UP_BUTTON		0x00090000
+#define HID_UP_ORDINAL		0x000a0000
 #define HID_UP_CONSUMER		0x000c0000
-#define HID_UP_DIGITIZER 	0x000d0000
-#define HID_UP_PID 		0x000f0000
+#define HID_UP_DIGITIZER	0x000d0000
+#define HID_UP_PID		0x000f0000
 #define HID_UP_HPVENDOR         0xff7f0000
 #define HID_UP_MSVENDOR		0xff000000
 
@@ -406,7 +406,7 @@
 	dma_addr_t outbuf_dma;						/* Output buffer dma */
 	spinlock_t outlock;						/* Output fifo spinlock */
 
-	unsigned claimed;						/* Claimed by hidinput, hiddev? */	
+	unsigned claimed;						/* Claimed by hidinput, hiddev? */
 	unsigned quirks;						/* Various quirks the device can pull on us */
 
 	struct list_head inputs;					/* The list of inputs */
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index 96b7c90..4c13331 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -95,7 +95,7 @@
 			return NULL;
 		rinfo->report_id = ((struct hid_report *) list)->id;
 		break;
-		
+
 	case HID_REPORT_ID_NEXT:
 		list = (struct list_head *)
 			report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK];
@@ -106,7 +106,7 @@
 			return NULL;
 		rinfo->report_id = ((struct hid_report *) list)->id;
 		break;
-		
+
 	default:
 		return NULL;
 	}
@@ -158,7 +158,7 @@
 		if (uref->field_index != HID_FIELD_INDEX_NONE ||
 		    (list->flags & HIDDEV_FLAG_REPORT) != 0) {
 			list->buffer[list->head] = *uref;
-			list->head = (list->head + 1) & 
+			list->head = (list->head + 1) &
 				(HIDDEV_BUFFER_SIZE - 1);
 			kill_fasync(&list->fasync, SIGIO, POLL_IN);
 		}
@@ -179,9 +179,9 @@
 	unsigned type = field->report_type;
 	struct hiddev_usage_ref uref;
 
-	uref.report_type = 
+	uref.report_type =
 	  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 
+	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
 	   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
 	uref.report_id = field->report->id;
 	uref.field_index = field->index;
@@ -199,9 +199,9 @@
 	struct hiddev_usage_ref uref;
 
 	memset(&uref, 0, sizeof(uref));
-	uref.report_type = 
+	uref.report_type =
 	  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 
+	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
 	   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
 	uref.report_id = report->id;
 	uref.field_index = HID_FIELD_INDEX_NONE;
@@ -236,7 +236,7 @@
 	*listptr = (*listptr)->next;
 
 	if (!--list->hiddev->open) {
-		if (list->hiddev->exist) 
+		if (list->hiddev->exist)
 			hid_close(list->hiddev->hid);
 		else
 			kfree(list->hiddev);
@@ -303,7 +303,7 @@
 		if (list->head == list->tail) {
 			add_wait_queue(&list->hiddev->wait, &wait);
 			set_current_state(TASK_INTERRUPTIBLE);
-			
+
 			while (list->head == list->tail) {
 				if (file->f_flags & O_NONBLOCK) {
 					retval = -EAGAIN;
@@ -317,7 +317,7 @@
 					retval = -EIO;
 					break;
 				}
-				
+
 				schedule();
 			}
 
@@ -329,7 +329,7 @@
 			return retval;
 
 
-		while (list->head != list->tail && 
+		while (list->head != list->tail &&
 		       retval + event_size <= count) {
 			if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
 				if (list->buffer[list->tail].field_index !=
@@ -405,10 +405,10 @@
 			return -EINVAL;
 
 		for (i = 0; i < hid->maxcollection; i++)
-			if (hid->collection[i].type == 
+			if (hid->collection[i].type ==
 			    HID_COLLECTION_APPLICATION && arg-- == 0)
 				break;
-		
+
 		if (i == hid->maxcollection)
 			return -EINVAL;
 
@@ -562,7 +562,7 @@
 		if (!uref_multi)
 			return -ENOMEM;
 		uref = &uref_multi->uref;
-		if (copy_from_user(uref, user_arg, sizeof(*uref))) 
+		if (copy_from_user(uref, user_arg, sizeof(*uref)))
 			goto fault;
 
 		rinfo.report_type = uref->report_type;
@@ -595,7 +595,7 @@
 			return -ENOMEM;
 		uref = &uref_multi->uref;
 		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-			if (copy_from_user(uref_multi, user_arg, 
+			if (copy_from_user(uref_multi, user_arg,
 					   sizeof(*uref_multi)))
 				goto fault;
 		} else {
@@ -603,7 +603,7 @@
 				goto fault;
 		}
 
-		if (cmd != HIDIOCGUSAGE && 
+		if (cmd != HIDIOCGUSAGE &&
 		    cmd != HIDIOCGUSAGES &&
 		    uref->report_type == HID_REPORT_TYPE_INPUT)
 			goto inval;
@@ -651,16 +651,16 @@
 				return field->usage[uref->usage_index].collection_index;
 			case HIDIOCGUSAGES:
 				for (i = 0; i < uref_multi->num_values; i++)
-					uref_multi->values[i] = 
+					uref_multi->values[i] =
 					    field->value[uref->usage_index + i];
-				if (copy_to_user(user_arg, uref_multi, 
+				if (copy_to_user(user_arg, uref_multi,
 						 sizeof(*uref_multi)))
 					goto fault;
 				goto goodreturn;
 			case HIDIOCSUSAGES:
 				for (i = 0; i < uref_multi->num_values; i++)
-					field->value[uref->usage_index + i] = 
-				  	    uref_multi->values[i];
+					field->value[uref->usage_index + i] =
+					    uref_multi->values[i];
 				goto goodreturn;
 		}
 
@@ -670,7 +670,7 @@
 fault:
 		kfree(uref_multi);
 		return -EFAULT;
-inval:		
+inval:
 		kfree(uref_multi);
 		return -EINVAL;
 
@@ -734,7 +734,7 @@
 	.name =		"usb/hid/hiddev%d",
 	.fops =		&hiddev_fops,
 	.mode =		S_IFCHR | S_IRUGO | S_IWUSR,
-       	.minor_base =	HIDDEV_MINOR_BASE,
+	.minor_base =	HIDDEV_MINOR_BASE,
 };
 
 /*
@@ -747,7 +747,7 @@
 	int retval;
 
 	for (i = 0; i < hid->maxcollection; i++)
-		if (hid->collection[i].type == 
+		if (hid->collection[i].type ==
 		    HID_COLLECTION_APPLICATION &&
 		    !IS_INPUT_APPLICATION(hid->collection[i].usage))
 			break;
@@ -755,11 +755,11 @@
 	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
 		return -1;
 
- 	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
 		return -1;
 	memset(hiddev, 0, sizeof(struct hiddev));
 
- 	retval = usb_register_dev(hid->intf, &hiddev_class);
+	retval = usb_register_dev(hid->intf, &hiddev_class);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		kfree(hiddev);
@@ -768,12 +768,12 @@
 
 	init_waitqueue_head(&hiddev->wait);
 
- 	hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+	hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
 
 	hiddev->hid = hid;
 	hiddev->exist = 1;
 
- 	hid->minor = hid->intf->minor;
+	hid->minor = hid->intf->minor;
 	hid->hiddev = hiddev;
 
 	return 0;
@@ -818,7 +818,7 @@
 /* We never attach in this manner, and rely on HID to connect us.  This
  * is why there is no disconnect routine defined in the usb_driver either.
  */
-static int hiddev_usbd_probe(struct usb_interface *intf, 
+static int hiddev_usbd_probe(struct usb_interface *intf,
 			     const struct usb_device_id *hiddev_info)
 {
 	return -ENODEV;
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
new file mode 100644
index 0000000..47dec6a
--- /dev/null
+++ b/drivers/usb/input/itmtouch.c
@@ -0,0 +1,268 @@
+/******************************************************************************
+ * itmtouch.c  --  Driver for ITM touchscreen panel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based upon original work by Chris Collins <xfire-itmtouch@xware.cx>.
+ *
+ * Kudos to ITM for providing me with the datasheet for the panel,
+ * even though it was a day later than I had finished writing this
+ * driver.
+ *
+ * It has meant that I've been able to correct my interpretation of the
+ * protocol packets however.
+ *
+ * CC -- 2003/9/29
+ *
+ * History
+ * 1.0 & 1.1  2003 (CC) vojtech@suse.cz
+ *   Original version for 2.4.x kernels
+ *
+ * 1.2  02/03/2005 (HCE) hc@mivu.no
+ *   Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints.
+ *   Unfortunately no calibration support at this time.
+ *
+ * 1.2.1  09/03/2005 (HCE) hc@mivu.no
+ *   Code cleanup and adjusting syntax to start matching kernel standards
+ *
+ *****************************************************************************/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/* only an 8 byte buffer necessary for a single packet */
+#define ITM_BUFSIZE			8
+#define PATH_SIZE			64
+
+#define USB_VENDOR_ID_ITMINC		0x0403
+#define USB_PRODUCT_ID_TOUCHPANEL	0xf9e9
+
+#define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc@mivu.no>"
+#define DRIVER_VERSION "v1.2.1"
+#define DRIVER_DESC "USB ITM Inc Touch Panel Driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE( DRIVER_LICENSE );
+
+struct itmtouch_dev {
+	struct usb_device	*usbdev; /* usb device */
+	struct input_dev	inputdev; /* input device */
+	struct urb		*readurb; /* urb */
+	char			rbuf[ITM_BUFSIZE]; /* data */
+	int			users;
+	char name[128];
+	char phys[64];
+};
+
+static struct usb_device_id itmtouch_ids [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) },
+	{ }
+};
+
+static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
+{
+	struct itmtouch_dev * itmtouch = urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	struct input_dev *dev = &itmtouch->inputdev;
+	int retval;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ETIMEDOUT:
+		/* this urb is timing out */
+		dbg("%s - urb timed out - was the device unplugged?",
+		    __FUNCTION__);
+		return;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+		    __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+		    __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	input_regs(dev, regs);
+
+	/* if pressure has been released, then don't report X/Y */
+	if (data[7] & 0x20) {
+		input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F));
+		input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F));
+	}
+
+	input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F));
+	input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20);
+	input_sync(dev);
+
+exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		printk(KERN_ERR "%s - usb_submit_urb failed with result: %d",
+				__FUNCTION__, retval);
+}
+
+static int itmtouch_open(struct input_dev *input)
+{
+	struct itmtouch_dev *itmtouch = input->private;
+
+	itmtouch->readurb->dev = itmtouch->usbdev;
+
+	if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void itmtouch_close(struct input_dev *input)
+{
+	struct itmtouch_dev *itmtouch = input->private;
+
+	usb_kill_urb(itmtouch->readurb);
+}
+
+static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct itmtouch_dev *itmtouch;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	unsigned int pipe;
+	unsigned int maxp;
+	char path[PATH_SIZE];
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+
+	if (!(itmtouch = kcalloc(1, sizeof(struct itmtouch_dev), GFP_KERNEL))) {
+		err("%s - Out of memory.", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	itmtouch->usbdev = udev;
+
+	itmtouch->inputdev.private = itmtouch;
+	itmtouch->inputdev.open = itmtouch_open;
+	itmtouch->inputdev.close = itmtouch_close;
+
+	usb_make_path(udev, path, PATH_SIZE);
+
+	itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+	itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	itmtouch->inputdev.name = itmtouch->name;
+	itmtouch->inputdev.phys = itmtouch->phys;
+	itmtouch->inputdev.id.bustype = BUS_USB;
+	itmtouch->inputdev.id.vendor = udev->descriptor.idVendor;
+	itmtouch->inputdev.id.product = udev->descriptor.idProduct;
+	itmtouch->inputdev.id.version = udev->descriptor.bcdDevice;
+	itmtouch->inputdev.dev = &intf->dev;
+
+	if (!strlen(itmtouch->name))
+		sprintf(itmtouch->name, "USB ITM touchscreen");
+
+	/* device limits */
+	/* as specified by the ITM datasheet, X and Y are 12bit,
+	 * Z (pressure) is 8 bit. However, the fields are defined up
+	 * to 14 bits for future possible expansion.
+	 */
+	input_set_abs_params(&itmtouch->inputdev, ABS_X, 0, 0x0FFF, 2, 0);
+	input_set_abs_params(&itmtouch->inputdev, ABS_Y, 0, 0x0FFF, 2, 0);
+	input_set_abs_params(&itmtouch->inputdev, ABS_PRESSURE, 0, 0xFF, 2, 0);
+
+	/* initialise the URB so we can read from the transport stream */
+	pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	if (maxp > ITM_BUFSIZE)
+		maxp = ITM_BUFSIZE;
+
+	itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL);
+
+	if (!itmtouch->readurb) {
+		dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__);
+		kfree(itmtouch);
+		return -ENOMEM;
+	}
+
+	usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf,
+			 maxp, itmtouch_irq, itmtouch, endpoint->bInterval);
+
+	input_register_device(&itmtouch->inputdev);
+
+	printk(KERN_INFO "itmtouch: %s registered on %s\n", itmtouch->name, path);
+	usb_set_intfdata(intf, itmtouch);
+
+	return 0;
+}
+
+static void itmtouch_disconnect(struct usb_interface *intf)
+{
+	struct itmtouch_dev *itmtouch = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+
+	if (itmtouch) {
+		input_unregister_device(&itmtouch->inputdev);
+		usb_kill_urb(itmtouch->readurb);
+		usb_free_urb(itmtouch->readurb);
+		kfree(itmtouch);
+	}
+}
+
+MODULE_DEVICE_TABLE(usb, itmtouch_ids);
+
+static struct usb_driver itmtouch_driver = {
+	.owner =        THIS_MODULE,
+	.name =         "itmtouch",
+	.probe =        itmtouch_probe,
+	.disconnect =   itmtouch_disconnect,
+	.id_table =     itmtouch_ids,
+};
+
+static int __init itmtouch_init(void)
+{
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	info(DRIVER_AUTHOR);
+	return usb_register(&itmtouch_driver);
+}
+
+static void __exit itmtouch_exit(void)
+{
+	usb_deregister(&itmtouch_driver);
+}
+
+module_init(itmtouch_init);
+module_exit(itmtouch_exit);
diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c
index a68c5b4..d2f0f90 100644
--- a/drivers/usb/input/kbtab.c
+++ b/drivers/usb/input/kbtab.c
@@ -36,7 +36,6 @@
 	struct input_dev dev;
 	struct usb_device *usbdev;
 	struct urb *irq;
-	int open;
 	int x, y;
 	int button;
 	int pressure;
@@ -79,12 +78,12 @@
 	/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
 	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
 
-	if( -1 == kb_pressure_click){ 
+	if (-1 == kb_pressure_click) {
 		input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
 	} else {
 		input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
 	};
-	
+
 	input_sync(dev);
 
  exit:
@@ -105,14 +104,9 @@
 {
 	struct kbtab *kbtab = dev->private;
 
-	if (kbtab->open++)
-		return 0;
-
 	kbtab->irq->dev = kbtab->usbdev;
-	if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) {
-		kbtab->open--;
+	if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
 		return -EIO;
-	}
 
 	return 0;
 }
@@ -121,8 +115,7 @@
 {
 	struct kbtab *kbtab = dev->private;
 
-	if (!--kbtab->open)
-		usb_kill_urb(kbtab->irq);
+	usb_kill_urb(kbtab->irq);
 }
 
 static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -161,7 +154,7 @@
 	kbtab->dev.absmax[ABS_X] = 0x2000;
 	kbtab->dev.absmax[ABS_Y] = 0x1750;
 	kbtab->dev.absmax[ABS_PRESSURE] = 0xff;
-	
+
 	kbtab->dev.absfuzz[ABS_X] = 4;
 	kbtab->dev.absfuzz[ABS_Y] = 4;
 
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
index ab1a2a3..09b5cc7 100644
--- a/drivers/usb/input/mtouchusb.c
+++ b/drivers/usb/input/mtouchusb.c
@@ -42,9 +42,9 @@
 #include <linux/config.h>
 
 #ifdef CONFIG_USB_DEBUG
-        #define DEBUG
+	#define DEBUG
 #else
-        #undef DEBUG
+	#undef DEBUG
 #endif
 
 #include <linux/kernel.h>
@@ -93,275 +93,255 @@
 MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)");
 
 struct mtouch_usb {
-        unsigned char *data;
-        dma_addr_t data_dma;
-        struct urb *irq;
-        struct usb_device *udev;
-        struct input_dev input;
-        int open;
-        char name[128];
-        char phys[64];
+	unsigned char *data;
+	dma_addr_t data_dma;
+	struct urb *irq;
+	struct usb_device *udev;
+	struct input_dev input;
+	char name[128];
+	char phys[64];
 };
 
-static struct usb_device_id mtouchusb_devices [] = {
-        { USB_DEVICE(0x0596, 0x0001) },
-        { }
+static struct usb_device_id mtouchusb_devices[] = {
+	{ USB_DEVICE(0x0596, 0x0001) },
+	{ }
 };
 
 static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
 {
-        struct mtouch_usb *mtouch = urb->context;
-        int retval;
+	struct mtouch_usb *mtouch = urb->context;
+	int retval;
 
-        switch (urb->status) {
-                case 0:
-                        /* success */
-                        break;
-                case -ETIMEDOUT:
-                        /* this urb is timing out */
-                        dbg("%s - urb timed out - was the device unplugged?",
-                            __FUNCTION__);
-                        return;
-                case -ECONNRESET:
-                case -ENOENT:
-                case -ESHUTDOWN:
-                        /* this urb is terminated, clean up */
-                        dbg("%s - urb shutting down with status: %d",
-                            __FUNCTION__, urb->status);
-                        return;
-                default:
-                        dbg("%s - nonzero urb status received: %d",
-                            __FUNCTION__, urb->status);
-                        goto exit;
-        }
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ETIMEDOUT:
+		/* this urb is timing out */
+		dbg("%s - urb timed out - was the device unplugged?",
+		    __FUNCTION__);
+		return;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+		    __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+		    __FUNCTION__, urb->status);
+		goto exit;
+	}
 
-        input_regs(&mtouch->input, regs);
-        input_report_key(&mtouch->input, BTN_TOUCH,
-                         MTOUCHUSB_GET_TOUCHED(mtouch->data));
-        input_report_abs(&mtouch->input, ABS_X,
-                         MTOUCHUSB_GET_XC(mtouch->data));
-        input_report_abs(&mtouch->input, ABS_Y,
+	input_regs(&mtouch->input, regs);
+	input_report_key(&mtouch->input, BTN_TOUCH,
+			 MTOUCHUSB_GET_TOUCHED(mtouch->data));
+	input_report_abs(&mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data));
+	input_report_abs(&mtouch->input, ABS_Y,
 			 (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC)
-                         - MTOUCHUSB_GET_YC(mtouch->data));
-        input_sync(&mtouch->input);
+			 - MTOUCHUSB_GET_YC(mtouch->data));
+	input_sync(&mtouch->input);
 
 exit:
-        retval = usb_submit_urb (urb, GFP_ATOMIC);
-        if (retval)
-                err ("%s - usb_submit_urb failed with result: %d",
-                     __FUNCTION__, retval);
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result: %d",
+		    __FUNCTION__, retval);
 }
 
-static int mtouchusb_open (struct input_dev *input)
+static int mtouchusb_open(struct input_dev *input)
 {
-        struct mtouch_usb *mtouch = input->private;
+	struct mtouch_usb *mtouch = input->private;
 
-        if (mtouch->open++)
-                return 0;
+	mtouch->irq->dev = mtouch->udev;
 
-        mtouch->irq->dev = mtouch->udev;
+	if (usb_submit_urb(mtouch->irq, GFP_ATOMIC))
+		return -EIO;
 
-        if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) {
-                mtouch->open--;
-                return -EIO;
-        }
-
-        return 0;
+	return 0;
 }
 
-static void mtouchusb_close (struct input_dev *input)
+static void mtouchusb_close(struct input_dev *input)
 {
-        struct mtouch_usb *mtouch = input->private;
+	struct mtouch_usb *mtouch = input->private;
 
-        if (!--mtouch->open)
-                usb_kill_urb (mtouch->irq);
+	usb_kill_urb(mtouch->irq);
 }
 
 static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
 {
-        dbg("%s - called", __FUNCTION__);
+	dbg("%s - called", __FUNCTION__);
 
-        mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
-                                        SLAB_ATOMIC, &mtouch->data_dma);
+	mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
+					SLAB_ATOMIC, &mtouch->data_dma);
 
-        if (!mtouch->data)
-                return -1;
+	if (!mtouch->data)
+		return -1;
 
-        return 0;
+	return 0;
 }
 
 static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
 {
-        dbg("%s - called", __FUNCTION__);
+	dbg("%s - called", __FUNCTION__);
 
-        if (mtouch->data)
-                usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
-                                mtouch->data, mtouch->data_dma);
+	if (mtouch->data)
+		usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
+				mtouch->data, mtouch->data_dma);
 }
 
 static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-        struct mtouch_usb *mtouch;
-        struct usb_host_interface *interface;
-        struct usb_endpoint_descriptor *endpoint;
-        struct usb_device *udev = interface_to_usbdev (intf);
-        char path[64];
-        int nRet;
+	struct mtouch_usb *mtouch;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	char path[64];
+	int nRet;
 
-        dbg("%s - called", __FUNCTION__);
+	dbg("%s - called", __FUNCTION__);
 
-        dbg("%s - setting interface", __FUNCTION__);
-        interface = intf->cur_altsetting;
+	dbg("%s - setting interface", __FUNCTION__);
+	interface = intf->cur_altsetting;
 
-        dbg("%s - setting endpoint", __FUNCTION__);
-        endpoint = &interface->endpoint[0].desc;
+	dbg("%s - setting endpoint", __FUNCTION__);
+	endpoint = &interface->endpoint[0].desc;
 
-        if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) {
-                err("%s - Out of memory.", __FUNCTION__);
-                return -ENOMEM;
-        }
+	if (!(mtouch = kmalloc(sizeof(struct mtouch_usb), GFP_KERNEL))) {
+		err("%s - Out of memory.", __FUNCTION__);
+		return -ENOMEM;
+	}
 
-        memset(mtouch, 0, sizeof(struct mtouch_usb));
-        mtouch->udev = udev;
+	memset(mtouch, 0, sizeof(struct mtouch_usb));
+	mtouch->udev = udev;
 
-        dbg("%s - allocating buffers", __FUNCTION__);
-        if (mtouchusb_alloc_buffers(udev, mtouch)) {
-                mtouchusb_free_buffers(udev, mtouch);
-                kfree(mtouch);
-                return -ENOMEM;
-        }
+	dbg("%s - allocating buffers", __FUNCTION__);
+	if (mtouchusb_alloc_buffers(udev, mtouch)) {
+		mtouchusb_free_buffers(udev, mtouch);
+		kfree(mtouch);
+		return -ENOMEM;
+	}
 
-        mtouch->input.private = mtouch;
-        mtouch->input.open = mtouchusb_open;
-        mtouch->input.close = mtouchusb_close;
+	mtouch->input.private = mtouch;
+	mtouch->input.open = mtouchusb_open;
+	mtouch->input.close = mtouchusb_close;
 
-        usb_make_path(udev, path, 64);
-        sprintf(mtouch->phys, "%s/input0", path);
+	usb_make_path(udev, path, 64);
+	sprintf(mtouch->phys, "%s/input0", path);
 
-        mtouch->input.name = mtouch->name;
-        mtouch->input.phys = mtouch->phys;
-        mtouch->input.id.bustype = BUS_USB;
-        mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
-        mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
-        mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
-        mtouch->input.dev = &intf->dev;
+	mtouch->input.name = mtouch->name;
+	mtouch->input.phys = mtouch->phys;
+	mtouch->input.id.bustype = BUS_USB;
+	mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
+	mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
+	mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
+	mtouch->input.dev = &intf->dev;
 
-        mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-        mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-        mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+	mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+	mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
 
-        /* Used to Scale Compensated Data and Flip Y */
-        mtouch->input.absmin[ABS_X] =  MTOUCHUSB_MIN_XC;
-        mtouch->input.absmax[ABS_X] =  raw_coordinates ? \
-                                       MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
-        mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
-        mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
-        mtouch->input.absmin[ABS_Y] =  MTOUCHUSB_MIN_YC;
-        mtouch->input.absmax[ABS_Y] =  raw_coordinates ? \
-                                       MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
-        mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
-        mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
+	/* Used to Scale Compensated Data and Flip Y */
+	mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC;
+	mtouch->input.absmax[ABS_X] = raw_coordinates ?
+					MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
+	mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
+	mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
+	mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC;
+	mtouch->input.absmax[ABS_Y] = raw_coordinates ?
+					MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
+	mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
+	mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
 
 	if (udev->manufacturer)
 		strcat(mtouch->name, udev->manufacturer);
 	if (udev->product)
 		sprintf(mtouch->name, "%s %s", mtouch->name, udev->product);
 
-        if (!strlen(mtouch->name))
-                sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
-                        mtouch->input.id.vendor, mtouch->input.id.product);
+	if (!strlen(mtouch->name))
+		sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
+			mtouch->input.id.vendor, mtouch->input.id.product);
 
-        nRet = usb_control_msg(mtouch->udev,
-                               usb_rcvctrlpipe(udev, 0),
-                               MTOUCHUSB_RESET,
-                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               1,
-                               0,
-                               NULL,
-                               0,
-                               USB_CTRL_SET_TIMEOUT);
-        dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
-            __FUNCTION__, nRet);
+	nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
+			       MTOUCHUSB_RESET,
+			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			       1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+	dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
+	    __FUNCTION__, nRet);
 
-        dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
-        mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
-        if (!mtouch->irq) {
-                dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
-                mtouchusb_free_buffers(udev, mtouch);
-                kfree(mtouch);
-                return -ENOMEM;
-        }
+	dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
+	mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!mtouch->irq) {
+		dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
+		mtouchusb_free_buffers(udev, mtouch);
+		kfree(mtouch);
+		return -ENOMEM;
+	}
 
-        dbg("%s - usb_fill_int_urb", __FUNCTION__);
-        usb_fill_int_urb(mtouch->irq,
-                         mtouch->udev,
-                         usb_rcvintpipe(mtouch->udev, 0x81),
-                         mtouch->data,
-                         MTOUCHUSB_REPORT_DATA_SIZE,
-                         mtouchusb_irq,
-                         mtouch,
-                         endpoint->bInterval);
+	dbg("%s - usb_fill_int_urb", __FUNCTION__);
+	usb_fill_int_urb(mtouch->irq, mtouch->udev,
+			 usb_rcvintpipe(mtouch->udev, 0x81),
+			 mtouch->data, MTOUCHUSB_REPORT_DATA_SIZE,
+			 mtouchusb_irq, mtouch, endpoint->bInterval);
 
-        dbg("%s - input_register_device", __FUNCTION__);
-        input_register_device(&mtouch->input);
+	dbg("%s - input_register_device", __FUNCTION__);
+	input_register_device(&mtouch->input);
 
-        nRet = usb_control_msg(mtouch->udev,
-                               usb_rcvctrlpipe(udev, 0),
-                               MTOUCHUSB_ASYNC_REPORT,
-                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               1,
-                               1,
-                               NULL,
-                               0,
-                               USB_CTRL_SET_TIMEOUT);
-        dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
-            __FUNCTION__, nRet);
+	nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
+			       MTOUCHUSB_ASYNC_REPORT,
+			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			       1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
+	dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
+	    __FUNCTION__, nRet);
 
-        printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
-        usb_set_intfdata(intf, mtouch);
+	printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
+	usb_set_intfdata(intf, mtouch);
 
-        return 0;
+	return 0;
 }
 
 static void mtouchusb_disconnect(struct usb_interface *intf)
 {
-        struct mtouch_usb *mtouch = usb_get_intfdata (intf);
+	struct mtouch_usb *mtouch = usb_get_intfdata(intf);
 
-        dbg("%s - called", __FUNCTION__);
-        usb_set_intfdata(intf, NULL);
-        if (mtouch) {
-                dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
-                usb_kill_urb(mtouch->irq);
-                input_unregister_device(&mtouch->input);
-                usb_free_urb(mtouch->irq);
-                mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
-                kfree(mtouch);
-        }
+	dbg("%s - called", __FUNCTION__);
+	usb_set_intfdata(intf, NULL);
+	if (mtouch) {
+		dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
+		usb_kill_urb(mtouch->irq);
+		input_unregister_device(&mtouch->input);
+		usb_free_urb(mtouch->irq);
+		mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
+		kfree(mtouch);
+	}
 }
 
-MODULE_DEVICE_TABLE (usb, mtouchusb_devices);
+MODULE_DEVICE_TABLE(usb, mtouchusb_devices);
 
 static struct usb_driver mtouchusb_driver = {
-        .owner =      THIS_MODULE,
-        .name =       "mtouchusb",
-        .probe =      mtouchusb_probe,
-        .disconnect = mtouchusb_disconnect,
-        .id_table =   mtouchusb_devices,
+	.owner		= THIS_MODULE,
+	.name		= "mtouchusb",
+	.probe		= mtouchusb_probe,
+	.disconnect	= mtouchusb_disconnect,
+	.id_table	= mtouchusb_devices,
 };
 
-static int __init mtouchusb_init(void) {
-        dbg("%s - called", __FUNCTION__);
-        return usb_register(&mtouchusb_driver);
+static int __init mtouchusb_init(void)
+{
+	dbg("%s - called", __FUNCTION__);
+	return usb_register(&mtouchusb_driver);
 }
 
-static void __exit mtouchusb_cleanup(void) {
-        dbg("%s - called", __FUNCTION__);
-        usb_deregister(&mtouchusb_driver);
+static void __exit mtouchusb_cleanup(void)
+{
+	dbg("%s - called", __FUNCTION__);
+	usb_deregister(&mtouchusb_driver);
 }
 
 module_init(mtouchusb_init);
 module_exit(mtouchusb_cleanup);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
index 7fa2f9b..3975b30 100644
--- a/drivers/usb/input/powermate.c
+++ b/drivers/usb/input/powermate.c
@@ -10,7 +10,7 @@
  * back to the host when polled by the USB controller.
  *
  * Testing with the knob I have has shown that it measures approximately 94 "clicks"
- * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was 
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
  * a variable speed cordless electric drill) has shown that the device can measure
  * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
  * the host. If it counts more than 7 clicks before it is polled, it will wrap back
@@ -120,9 +120,9 @@
 /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
 static void powermate_sync_state(struct powermate_device *pm)
 {
-	if (pm->requires_update == 0) 
+	if (pm->requires_update == 0)
 		return; /* no updates are required */
-	if (pm->config->status == -EINPROGRESS) 
+	if (pm->config->status == -EINPROGRESS)
 		return; /* an update is already in progress; it'll issue this update when it completes */
 
 	if (pm->requires_update & UPDATE_PULSE_ASLEEP){
@@ -142,7 +142,7 @@
 		   2: multiply the speed
 		   the argument only has an effect for operations 0 and 2, and ranges between
 		   1 (least effect) to 255 (maximum effect).
-       
+
 		   thus, several states are equivalent and are coalesced into one state.
 
 		   we map this onto a range from 0 to 510, with:
@@ -151,7 +151,7 @@
 		   256 -- 510  -- use multiple (510 = fastest).
 
 		   Only values of 'arg' quite close to 255 are particularly useful/spectacular.
-		*/    
+		*/
 		if (pm->pulse_speed < 255){
 			op = 0;                   // divide
 			arg = 255 - pm->pulse_speed;
@@ -199,14 +199,14 @@
 
 	if (urb->status)
 		printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
-	
+
 	spin_lock_irqsave(&pm->lock, flags);
 	powermate_sync_state(pm);
 	spin_unlock_irqrestore(&pm->lock, flags);
 }
 
 /* Set the LED up as described and begin the sync with the hardware if required */
-static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, 
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
 				int pulse_table, int pulse_asleep, int pulse_awake)
 {
 	unsigned long flags;
@@ -229,7 +229,7 @@
 	/* mark state updates which are required */
 	if (static_brightness != pm->static_brightness){
 		pm->static_brightness = static_brightness;
-		pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;		
+		pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
 	}
 	if (pulse_asleep != pm->pulse_asleep){
 		pm->pulse_asleep = pulse_asleep;
@@ -246,7 +246,7 @@
 	}
 
 	powermate_sync_state(pm);
-   
+
 	spin_unlock_irqrestore(&pm->lock, flags);
 }
 
@@ -257,19 +257,19 @@
 	struct powermate_device *pm = dev->private;
 
 	if (type == EV_MSC && code == MSC_PULSELED){
-		/*  
+		/*
 		    bits  0- 7: 8 bits: LED brightness
 		    bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
 		    bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
 		    bit     19: 1 bit : pulse whilst asleep?
 		    bit     20: 1 bit : pulse constantly?
-		*/  
+		*/
 		int static_brightness = command & 0xFF;   // bits 0-7
 		int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
 		int pulse_table = (command >> 17) & 0x3;  // bits 17-18
 		int pulse_asleep = (command >> 19) & 0x1; // bit 19
 		int pulse_awake  = (command >> 20) & 0x1; // bit 20
-  
+
 		powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
 	}
 
@@ -378,7 +378,7 @@
 	switch (le16_to_cpu(udev->descriptor.idProduct)) {
 	case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break;
 	case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break;
-	default: 
+	default:
 		pm->input.name = pm_name_soundknob;
 		printk(KERN_WARNING "powermate: unknown product id %04x\n",
 		       le16_to_cpu(udev->descriptor.idProduct));
@@ -402,11 +402,11 @@
 	usb_make_path(udev, path, 64);
 	snprintf(pm->phys, 64, "%s/input0", path);
 	printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys);
-	
+
 	/* force an update of everything */
 	pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
 	powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
-  
+
 	usb_set_intfdata(intf, pm);
 	return 0;
 }
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
index a71f1bb..386595e 100644
--- a/drivers/usb/input/touchkitusb.c
+++ b/drivers/usb/input/touchkitusb.c
@@ -69,7 +69,6 @@
 	struct urb *irq;
 	struct usb_device *udev;
 	struct input_dev input;
-	int open;
 	char name[128];
 	char phys[64];
 };
@@ -134,15 +133,10 @@
 {
 	struct touchkit_usb *touchkit = input->private;
 
-	if (touchkit->open++)
-		return 0;
-
 	touchkit->irq->dev = touchkit->udev;
 
-	if (usb_submit_urb(touchkit->irq, GFP_ATOMIC)) {
-		touchkit->open--;
+	if (usb_submit_urb(touchkit->irq, GFP_ATOMIC))
 		return -EIO;
-	}
 
 	return 0;
 }
@@ -151,8 +145,7 @@
 {
 	struct touchkit_usb *touchkit = input->private;
 
-	if (!--touchkit->open)
-		usb_kill_urb(touchkit->irq);
+	usb_kill_urb(touchkit->irq);
 }
 
 static int touchkit_alloc_buffers(struct usb_device *udev,
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
index 7038fb9..f35db19 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -9,18 +9,18 @@
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -72,7 +72,6 @@
 	unsigned char newleds;
 	char name[128];
 	char phys[64];
-	int open;
 
 	unsigned char *new;
 	struct usb_ctrlrequest *cr;
@@ -166,7 +165,7 @@
 
 	if (urb->status)
 		warn("led urb status %d received", urb->status);
-	
+
 	if (*(kbd->leds) == kbd->newleds)
 		return;
 
@@ -180,14 +179,9 @@
 {
 	struct usb_kbd *kbd = dev->private;
 
-	if (kbd->open++)
-		return 0;
-
 	kbd->irq->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->irq, GFP_KERNEL)) {
-		kbd->open--;
+	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
 		return -EIO;
-	}
 
 	return 0;
 }
@@ -196,8 +190,7 @@
 {
 	struct usb_kbd *kbd = dev->private;
 
-	if (!--kbd->open)
-		usb_kill_urb(kbd->irq);
+	usb_kill_urb(kbd->irq);
 }
 
 static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
@@ -230,7 +223,7 @@
 		usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
 }
 
-static int usb_kbd_probe(struct usb_interface *iface, 
+static int usb_kbd_probe(struct usb_interface *iface,
 			 const struct usb_device_id *id)
 {
 	struct usb_device * dev = interface_to_usbdev(iface);
@@ -272,7 +265,7 @@
 	for (i = 0; i < 255; i++)
 		set_bit(usb_kbd_keycode[i], kbd->dev.keybit);
 	clear_bit(0, kbd->dev.keybit);
-	
+
 	kbd->dev.private = kbd;
 	kbd->dev.event = usb_kbd_event;
 	kbd->dev.open = usb_kbd_open;
@@ -294,7 +287,7 @@
 	sprintf(kbd->phys, "%s/input0", path);
 
 	kbd->dev.name = kbd->name;
-	kbd->dev.phys = kbd->phys;	
+	kbd->dev.phys = kbd->phys;
 	kbd->dev.id.bustype = BUS_USB;
 	kbd->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
 	kbd->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
@@ -329,7 +322,7 @@
 static void usb_kbd_disconnect(struct usb_interface *intf)
 {
 	struct usb_kbd *kbd = usb_get_intfdata (intf);
-	
+
 	usb_set_intfdata(intf, NULL);
 	if (kbd) {
 		usb_kill_urb(kbd->irq);
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 01155bb..1ec41b5 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -9,18 +9,18 @@
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -51,7 +51,6 @@
 	struct usb_device *usbdev;
 	struct input_dev dev;
 	struct urb *irq;
-	int open;
 
 	signed char *data;
 	dma_addr_t data_dma;
@@ -101,14 +100,9 @@
 {
 	struct usb_mouse *mouse = dev->private;
 
-	if (mouse->open++)
-		return 0;
-
 	mouse->irq->dev = mouse->usbdev;
-	if (usb_submit_urb(mouse->irq, GFP_KERNEL)) {
-		mouse->open--;
+	if (usb_submit_urb(mouse->irq, GFP_KERNEL))
 		return -EIO;
-	}
 
 	return 0;
 }
@@ -117,8 +111,7 @@
 {
 	struct usb_mouse *mouse = dev->private;
 
-	if (!--mouse->open)
-		usb_kill_urb(mouse->irq);
+	usb_kill_urb(mouse->irq);
 }
 
 static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id)
@@ -132,19 +125,19 @@
 
 	interface = intf->cur_altsetting;
 
-	if (interface->desc.bNumEndpoints != 1) 
+	if (interface->desc.bNumEndpoints != 1)
 		return -ENODEV;
 
 	endpoint = &interface->endpoint[0].desc;
-	if (!(endpoint->bEndpointAddress & 0x80)) 
+	if (!(endpoint->bEndpointAddress & 0x80))
 		return -ENODEV;
-	if ((endpoint->bmAttributes & 3) != 3) 
+	if ((endpoint->bmAttributes & 3) != 3)
 		return -ENODEV;
 
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
-	if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) 
+	if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL)))
 		return -ENOMEM;
 	memset(mouse, 0, sizeof(struct usb_mouse));
 
@@ -209,7 +202,7 @@
 static void usb_mouse_disconnect(struct usb_interface *intf)
 {
 	struct usb_mouse *mouse = usb_get_intfdata (intf);
-	
+
 	usb_set_intfdata(intf, NULL);
 	if (mouse) {
 		usb_kill_urb(mouse->irq);
@@ -238,7 +231,7 @@
 static int __init usb_mouse_init(void)
 {
 	int retval = usb_register(&usb_mouse_driver);
-	if (retval == 0) 
+	if (retval == 0)
 		info(DRIVER_VERSION ":" DRIVER_DESC);
 	return retval;
 }
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
index fec04dd..f6b34af 100644
--- a/drivers/usb/input/wacom.c
+++ b/drivers/usb/input/wacom.c
@@ -9,7 +9,7 @@
  *  Copyright (c) 2000 Daniel Egger		<egger@suse.de>
  *  Copyright (c) 2001 Frederic Lepied		<flepied@mandrakesoft.com>
  *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@mech.kuleuven.ac.be>
- *  Copyright (c) 2002-2004 Ping Cheng		<pingc@wacom.com>
+ *  Copyright (c) 2002-2005 Ping Cheng		<pingc@wacom.com>
  *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
@@ -18,7 +18,7 @@
  *	v0.4 (sm)  - Support for more Intuos models, menustrip
  *			relative mode, proximity.
  *	v0.5 (vp)  - Big cleanup, nifty features removed,
- * 			they belong in userspace
+ *			they belong in userspace
  *	v1.8 (vp)  - Submit URB only when operating, moved to CVS,
  *			use input_report_key instead of report_btn and
  *			other cleanups
@@ -51,6 +51,9 @@
  *		   - Cleanups here and there
  *    v1.30.1 (pi) - Added Graphire3 support
  *	v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
+ *	v1.43 (pc) - Added support for Cintiq 21UX
+		   - Fixed a Graphire bug
+		   - Merged wacom_intuos3_irq into wacom_intuos_irq
  */
 
 /*
@@ -72,7 +75,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.40"
+#define DRIVER_VERSION "v1.43"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 #define DRIVER_LICENSE "GPL"
@@ -83,6 +86,16 @@
 
 #define USB_VENDOR_ID_WACOM	0x056a
 
+enum {
+	PENPARTNER = 0,
+	GRAPHIRE,
+	PL,
+	INTUOS,
+	INTUOS3,
+	CINTIQ,
+	MAX_TYPE
+};
+
 struct wacom_features {
 	char *name;
 	int pktlen;
@@ -102,7 +115,6 @@
 	struct urb *irq;
 	struct wacom_features *features;
 	int tool[2];
-	int open;
 	__u32 serial[2];
 	char phys[32];
 };
@@ -149,7 +161,7 @@
 	prox = data[1] & 0x40;
 
 	input_regs(dev, regs);
-	
+
 	if (prox) {
 
 		pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
@@ -166,8 +178,7 @@
 		if (!wacom->tool[0]) {
 			/* Going into proximity select tool */
 			wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-		}
-		else {
+		} else {
 			/* was entered with stylus2 pressed */
 			if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) {
 				/* report out proximity for previous tool */
@@ -182,16 +193,15 @@
 			wacom->tool[1] = BTN_TOOL_PEN;
 		}
 		input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */
-		input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14));
-		input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14));
+		input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+		input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
 		input_report_abs(dev, ABS_PRESSURE, pressure);
 
 		input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
 		input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
 		/* Only allow the stylus2 button to be reported for the pen tool. */
 		input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
-	}
-	else {
+	} else {
 		/* report proximity-out of a (valid) tool */
 		if (wacom->tool[1] != BTN_TOOL_RUBBER) {
 			/* Unknown tool selected default to pen tool */
@@ -203,7 +213,7 @@
 	wacom->tool[0] = prox; /* Save proximity state */
 	input_sync(dev);
 
-exit:
+ exit:
 	retval = usb_submit_urb (urb, GFP_ATOMIC);
 	if (retval)
 		err ("%s - usb_submit_urb failed with result %d",
@@ -232,20 +242,16 @@
 		goto exit;
 	}
 
-	if (data[0] != 2)
-	{
+	if (data[0] != 2) {
 		printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
 		goto exit;
 	}
 
 	input_regs(dev, regs);
-	if (data[1] & 0x04)
-	{
+	if (data[1] & 0x04) {
 		input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20);
 		input_report_key(dev, BTN_TOUCH, data[1] & 0x08);
-	}
-	else
-	{
+	} else {
 		input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
 		input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
 	}
@@ -257,7 +263,7 @@
 
 	input_sync(dev);
 
-exit:
+ exit:
 	retval = usb_submit_urb (urb, GFP_ATOMIC);
 	if (retval)
 		err ("%s - usb_submit_urb failed with result %d",
@@ -300,7 +306,7 @@
 	input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
 	input_sync(dev);
 
-exit:
+ exit:
 	retval = usb_submit_urb (urb, GFP_ATOMIC);
 	if (retval)
 		err ("%s - usb_submit_urb failed with result %d",
@@ -340,47 +346,47 @@
 
 	input_regs(dev, regs);
 
-	switch ((data[1] >> 5) & 3) {
+	if (data[1] & 0x10) { /* in prox */
 
-		case 0:	/* Pen */
-			input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x80);
-			break;
+		switch ((data[1] >> 5) & 3) {
 
-		case 1: /* Rubber */
-			input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
-			break;
+			case 0:	/* Pen */
+				wacom->tool[0] = BTN_TOOL_PEN;
+				break;
 
-		case 2: /* Mouse with wheel */
-			input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
-			input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
-			/* fall through */
+			case 1: /* Rubber */
+				wacom->tool[0] = BTN_TOOL_RUBBER;
+				break;
 
-                case 3: /* Mouse without wheel */
-			input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24);
-			input_report_key(dev, BTN_LEFT, data[1] & 0x01);
-			input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
-			input_report_abs(dev, ABS_DISTANCE, data[7]);
+			case 2: /* Mouse with wheel */
+				input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
+				input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+				/* fall through */
 
-			input_report_abs(dev, ABS_X, x);
-			input_report_abs(dev, ABS_Y, y);
-
-			input_sync(dev);
-			goto exit;
+			case 3: /* Mouse without wheel */
+				wacom->tool[0] = BTN_TOOL_MOUSE;
+				input_report_key(dev, BTN_LEFT, data[1] & 0x01);
+				input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
+				input_report_abs(dev, ABS_DISTANCE, data[7]);
+				break;
+		}
 	}
 
 	if (data[1] & 0x80) {
 		input_report_abs(dev, ABS_X, x);
 		input_report_abs(dev, ABS_Y, y);
 	}
+	if (wacom->tool[0] != BTN_TOOL_MOUSE) {
+		input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
+		input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
+		input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
+		input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
+	}
 
-	input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
-	input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
-	input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
-	input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
-
+	input_report_key(dev, wacom->tool[0], data[1] & 0x10);
 	input_sync(dev);
 
-exit:
+ exit:
 	retval = usb_submit_urb (urb, GFP_ATOMIC);
 	if (retval)
 		err ("%s - usb_submit_urb failed with result %d",
@@ -398,14 +404,13 @@
 	idx = data[1] & 0x01;
 
 	/* Enter report */
-	if ((data[1] & 0xfc) == 0xc0)
-	{
+	if ((data[1] & 0xfc) == 0xc0) {
 		/* serial number of the tool */
-		wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +
-			((__u32)data[4] << 20) + ((__u32)data[5] << 12) +
-			((__u32)data[6] << 4) + (data[7] >> 4);
+		wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+			(data[4] << 20) + (data[5] << 12) +
+			(data[6] << 4) + (data[7] >> 4);
 
-		switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
+		switch ((data[2] << 4) | (data[3] >> 4)) {
 			case 0x812: /* Inking pen */
 			case 0x801: /* Intuos3 Inking pen */
 			case 0x012:
@@ -449,7 +454,7 @@
 			case 0x112:
 			case 0x913: /* Intuos3 Airbrush */
 				wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
-				break;	/* Airbrush */
+				break;
 			default: /* Unknown tool */
 				wacom->tool[idx] = BTN_TOOL_PEN;
 		}
@@ -478,9 +483,8 @@
 	unsigned int t;
 
 	/* general pen packet */
-	if ((data[1] & 0xb8) == 0xa0)
-	{
-		t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+	if ((data[1] & 0xb8) == 0xa0) {
+		t = (data[6] << 2) | ((data[7] >> 6) & 3);
 		input_report_abs(dev, ABS_PRESSURE, t);
 		input_report_abs(dev, ABS_TILT_X,
 				((data[7] << 1) & 0x7e) | (data[8] >> 7));
@@ -491,10 +495,9 @@
 	}
 
 	/* airbrush second packet */
-	if ((data[1] & 0xbc) == 0xb4)
-	{
+	if ((data[1] & 0xbc) == 0xb4) {
 		input_report_abs(dev, ABS_WHEEL,
-				((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+				(data[6] << 2) | ((data[7] >> 6) & 3));
 		input_report_abs(dev, ABS_TILT_X,
 				((data[7] << 1) & 0x7e) | (data[8] >> 7));
 		input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
@@ -526,7 +529,7 @@
 		goto exit;
 	}
 
-	if (data[0] != 2 && data[0] != 5 && data[0] != 6) {
+	if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
 		dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
 		goto exit;
 	}
@@ -536,107 +539,10 @@
 	/* tool number */
 	idx = data[1] & 0x01;
 
-	/* process in/out prox events */
-	if (wacom_intuos_inout(urb)) goto exit;
-
-	input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
-	input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
-	input_report_abs(dev, ABS_DISTANCE, data[9]);
-
-	/* process general packets */
-	wacom_intuos_general(urb);
-	
-	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {		/* 4D mouse or Lens cursor packets */
-
-		if (data[1] & 0x02) {						/* Rotation packet */
-
-			t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
-			input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2);
-
-		} else {
-
-	 		if ((data[1] & 0x10) == 0) {				/* 4D mouse packets */
-
-				input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
-				input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
-				input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
-
-				input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
-				input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
-				t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
-				input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
-			} else {
-				if (wacom->tool[idx] == BTN_TOOL_MOUSE) {	/* 2D mouse packets */	
-					input_report_key(dev, BTN_LEFT,   data[8] & 0x04);
-					input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
-					input_report_key(dev, BTN_RIGHT,  data[8] & 0x10);
-					input_report_rel(dev, REL_WHEEL, 
-					    (-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1)));
-				}
-				else {     /* Lens cursor packets */
-					input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
-					input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
-					input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
-					input_report_key(dev, BTN_SIDE,   data[8] & 0x10);
-					input_report_key(dev, BTN_EXTRA,  data[8] & 0x08);
-				}
-			}
-		}
-	}
-	
-	input_report_key(dev, wacom->tool[idx], 1);
-	input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-	input_sync(dev);
-
-exit:
-	retval = usb_submit_urb (urb, GFP_ATOMIC);
-	if (retval)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, retval);
-}
-
-static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
-{
-	struct wacom *wacom = urb->context;
-	unsigned char *data = wacom->data;
-	struct input_dev *dev = &wacom->dev;
-	unsigned int t;
-	int idx, retval;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-		goto exit;
-	}
-
-	/* check for valid report */
-	if (data[0] != 2 && data[0] != 5 && data[0] != 12)
-	{
-		printk(KERN_INFO "wacom_intuos3_irq: received unknown report #%d\n", data[0]);
-		goto exit;
-	}
-
-	input_regs(dev, regs);
-
-	/* tool index is always 0 here since there is no dual input tool */
-	idx = data[1] & 0x01;
-
 	/* pad packets. Works as a second tool and is always in prox */
-	if (data[0] == 12)
-	{
+	if (data[0] == 12) {
 		/* initiate the pad as a device */
-		if (wacom->tool[1] != BTN_TOOL_FINGER)
-		{
+		if (wacom->tool[1] != BTN_TOOL_FINGER) {
 			wacom->tool[1] = BTN_TOOL_FINGER;
 			input_report_key(dev, wacom->tool[1], 1);
 		}
@@ -656,37 +562,78 @@
 	}
 
 	/* process in/out prox events */
-	if (wacom_intuos_inout(urb)) goto exit;
+	if (wacom_intuos_inout(urb))
+		goto exit;
 
-	input_report_abs(dev, ABS_X, ((__u32)data[2] << 9) | ((__u32)data[3] << 1) | ((data[9] >> 1) & 1));
-	input_report_abs(dev, ABS_Y, ((__u32)data[4] << 9) | ((__u32)data[5] << 1) | (data[9] & 1));
-	input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+	/* Cintiq doesn't send data when RDY bit isn't set */
+	if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+		return;
+
+	if (wacom->features->type >= INTUOS3) {
+		input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
+		input_report_abs(dev, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
+		input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+	} else {
+		input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
+		input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
+		input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
+	}
 
 	/* process general packets */
 	wacom_intuos_general(urb);
 
-	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0)
-	{
-		/* Marker pen rotation packet. Reported as wheel due to valuator limitation */
-		if (data[1] & 0x02)
-		{
-			t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
-			t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
-				((t-1) / 2 + 450)) : (450 - t / 2) ;
-			input_report_abs(dev, ABS_WHEEL, t);
-		}
+	/* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
+	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
 
-		/* 2D mouse packets */
-		if (wacom->tool[idx] == BTN_TOOL_MOUSE)
-		{
+		if (data[1] & 0x02) {
+			/* Rotation packet */
+			if (wacom->features->type >= INTUOS3) {
+				/* I3 marker pen rotation reported as wheel
+				 * due to valuator limitation
+				 */
+				t = (data[6] << 3) | ((data[7] >> 5) & 7);
+				t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+					((t-1) / 2 + 450)) : (450 - t / 2) ;
+				input_report_abs(dev, ABS_WHEEL, t);
+			} else {
+				/* 4D mouse rotation packet */
+				t = (data[6] << 3) | ((data[7] >> 5) & 7);
+				input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
+					((t - 1) / 2) : -t / 2);
+			}
+
+		} else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
+			/* 4D mouse packet */
+			input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
+			input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+			input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
+
+			input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
+			input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
+			t = (data[6] << 2) | ((data[7] >> 6) & 3);
+			input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+
+		} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+			/* 2D mouse packet */
 			input_report_key(dev, BTN_LEFT,   data[8] & 0x04);
 			input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
 			input_report_key(dev, BTN_RIGHT,  data[8] & 0x10);
-			input_report_key(dev, BTN_SIDE,   data[8] & 0x40);
-			input_report_key(dev, BTN_EXTRA,  data[8] & 0x20);
-			/* mouse wheel is positive when rolled backwards */
-			input_report_rel(dev, REL_WHEEL,  ((__u32)((data[8] & 0x02) >> 1)
-					 - (__u32)(data[8] & 0x01)));
+			input_report_rel(dev, REL_WHEEL, ((data[8] & 0x02) >> 1)
+						 - (data[8] & 0x01));
+
+			/* I3 2D mouse side buttons */
+			if (wacom->features->type == INTUOS3) {
+				input_report_key(dev, BTN_SIDE,   data[8] & 0x40);
+				input_report_key(dev, BTN_EXTRA,  data[8] & 0x20);
+			}
+
+		} else if (wacom->features->type < INTUOS3) {
+			/* Lens cursor packets */
+			input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
+			input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+			input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
+			input_report_key(dev, BTN_SIDE,   data[8] & 0x10);
+			input_report_key(dev, BTN_EXTRA,  data[8] & 0x08);
 		}
 	}
 
@@ -702,35 +649,36 @@
 }
 
 static struct wacom_features wacom_features[] = {
-	{ "Wacom Penpartner",    7,   5040,  3780,  255, 32, 0, wacom_penpartner_irq },
-        { "Wacom Graphire",      8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
-	{ "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
- 	{ "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, 1, wacom_graphire_irq },
-	{ "Wacom Graphire3",     8,  10208,  7424,  511, 32, 1, wacom_graphire_irq },
-	{ "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 32, 1, wacom_graphire_irq },
-  	{ "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 15, 2, wacom_intuos_irq },
- 	{ "Wacom PL400",         8,   5408,  4056,  255, 32, 3, wacom_pl_irq },
- 	{ "Wacom PL500",         8,   6144,  4608,  255, 32, 3, wacom_pl_irq },
- 	{ "Wacom PL600",         8,   6126,  4604,  255, 32, 3, wacom_pl_irq },
- 	{ "Wacom PL600SX",       8,   6260,  5016,  255, 32, 3, wacom_pl_irq },
- 	{ "Wacom PL550",         8,   6144,  4608,  511, 32, 3, wacom_pl_irq },
- 	{ "Wacom PL800",         8,   7220,  5780,  511, 32, 3, wacom_pl_irq },
-	{ "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq },
-	{ "Wacom Volito",        8,   5104,  3712,  511, 32, 1, wacom_graphire_irq },
-	{ "Wacom Cintiq Partner",8,  20480, 15360,  511, 32, 3, wacom_ptu_irq },
-	{ "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 15, 4, wacom_intuos3_irq },
-	{ "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq },
-	{ "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq },
-	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
- 	{ }
+	{ "Wacom Penpartner",    7,   5040,  3780,  255, 32, PENPARTNER, wacom_penpartner_irq },
+        { "Wacom Graphire",      8,  10206,  7422,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+	{ "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+	{ "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+	{ "Wacom Graphire3",     8,  10208,  7424,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+	{ "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+	{ "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom PL400",         8,   5408,  4056,  255, 32, PL,         wacom_pl_irq },
+	{ "Wacom PL500",         8,   6144,  4608,  255, 32, PL,         wacom_pl_irq },
+	{ "Wacom PL600",         8,   6126,  4604,  255, 32, PL,         wacom_pl_irq },
+	{ "Wacom PL600SX",       8,   6260,  5016,  255, 32, PL,         wacom_pl_irq },
+	{ "Wacom PL550",         8,   6144,  4608,  511, 32, PL,         wacom_pl_irq },
+	{ "Wacom PL800",         8,   7220,  5780,  511, 32, PL,         wacom_pl_irq },
+	{ "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ "Wacom Volito",        8,   5104,  3712,  511, 32, GRAPHIRE,   wacom_graphire_irq },
+	{ "Wacom Cintiq Partner",8,  20480, 15360,  511, 32, PL,         wacom_ptu_irq },
+	{ "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 15, INTUOS3,    wacom_intuos_irq },
+	{ "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 15, INTUOS3,    wacom_intuos_irq },
+	{ "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 15, INTUOS3,    wacom_intuos_irq },
+	{ "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 15, CINTIQ,     wacom_intuos_irq },
+	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, INTUOS,     wacom_intuos_irq },
+	{ }
 };
 
 static struct usb_device_id wacom_ids[] = {
@@ -761,6 +709,7 @@
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
 	{ }
 };
@@ -771,14 +720,9 @@
 {
 	struct wacom *wacom = dev->private;
 
-	if (wacom->open++)
-		return 0;
-
 	wacom->irq->dev = wacom->usbdev;
-	if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
-		wacom->open--;
+	if (usb_submit_urb(wacom->irq, GFP_KERNEL))
 		return -EIO;
-	}
 
 	return 0;
 }
@@ -787,8 +731,7 @@
 {
 	struct wacom *wacom = dev->private;
 
-	if (!--wacom->open)
-		usb_kill_urb(wacom->irq);
+	usb_kill_urb(wacom->irq);
 }
 
 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -823,32 +766,33 @@
 	wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
 
 	switch (wacom->features->type) {
-		case 1:
+		case GRAPHIRE:
 			wacom->dev.evbit[0] |= BIT(EV_REL);
 			wacom->dev.relbit[0] |= BIT(REL_WHEEL);
 			wacom->dev.absbit[0] |= BIT(ABS_DISTANCE);
 			wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
 			break;
 
-		case 4: /* new functions for Intuos3 */
+		case INTUOS3:
+		case CINTIQ:
 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
 			wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
 			wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY);
 			/* fall through */
 
-		case 2:
+		case INTUOS:
 			wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
 			wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
 			wacom->dev.relbit[0] |= BIT(REL_WHEEL);
 			wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
- 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE)	| BIT(BTN_TOOL_BRUSH)
+			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE)	| BIT(BTN_TOOL_BRUSH)
 							  | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
 			wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE);
 			break;
 
-		case 3:
- 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
+		case PL:
+			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
 			break;
 	}
 
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
index d65edb2..a7fa1b1 100644
--- a/drivers/usb/input/xpad.c
+++ b/drivers/usb/input/xpad.c
@@ -104,13 +104,12 @@
 struct usb_xpad {
 	struct input_dev dev;			/* input device interface */
 	struct usb_device *udev;		/* usb device */
-	
+
 	struct urb *irq_in;			/* urb for interrupt in report */
 	unsigned char *idata;			/* input data */
 	dma_addr_t idata_dma;
-	
+
 	char phys[65];				/* physical device path */
-	int open_count;				/* reference count */
 };
 
 /*
@@ -128,35 +127,35 @@
 	struct input_dev *dev = &xpad->dev;
 
 	input_regs(dev, regs);
-	
+
 	/* left stick */
 	input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
 	input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
-	
+
 	/* right stick */
 	input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
 	input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
-	
+
 	/* triggers left/right */
 	input_report_abs(dev, ABS_Z, data[10]);
 	input_report_abs(dev, ABS_RZ, data[11]);
-	
+
 	/* digital pad */
 	input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
 	input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
-	
+
 	/* start/back buttons and stick press left/right */
 	input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
 	input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
 	input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
 	input_report_key(dev, BTN_THUMBR, data[2] >> 7);
-	
+
 	/* "analog" buttons A, B, X, Y */
 	input_report_key(dev, BTN_A, data[4]);
 	input_report_key(dev, BTN_B, data[5]);
 	input_report_key(dev, BTN_X, data[6]);
 	input_report_key(dev, BTN_Y, data[7]);
-	
+
 	/* "analog" buttons black, white */
 	input_report_key(dev, BTN_C, data[8]);
 	input_report_key(dev, BTN_Z, data[9]);
@@ -168,7 +167,7 @@
 {
 	struct usb_xpad *xpad = urb->context;
 	int retval;
-	
+
 	switch (urb->status) {
 	case 0:
 		/* success */
@@ -183,7 +182,7 @@
 		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
 		goto exit;
 	}
-	
+
 	xpad_process_packet(xpad, 0, xpad->idata, regs);
 
 exit:
@@ -196,25 +195,19 @@
 static int xpad_open (struct input_dev *dev)
 {
 	struct usb_xpad *xpad = dev->private;
-	
-	if (xpad->open_count++)
-		return 0;
-	
+
 	xpad->irq_in->dev = xpad->udev;
-	if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) {
-		xpad->open_count--;
+	if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
 		return -EIO;
-	}
-	
+
 	return 0;
 }
 
 static void xpad_close (struct input_dev *dev)
 {
 	struct usb_xpad *xpad = dev->private;
-	
-	if (!--xpad->open_count)
-		usb_kill_urb(xpad->irq_in);
+
+	usb_kill_urb(xpad->irq_in);
 }
 
 static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -224,19 +217,19 @@
 	struct usb_endpoint_descriptor *ep_irq_in;
 	char path[64];
 	int i;
-	
+
 	for (i = 0; xpad_device[i].idVendor; i++) {
 		if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
 		    (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
 			break;
 	}
-	
+
 	if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) {
 		err("cannot allocate memory for new pad");
 		return -ENOMEM;
 	}
 	memset(xpad, 0, sizeof(struct usb_xpad));
-	
+
 	xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
 				       SLAB_ATOMIC, &xpad->idata_dma);
 	if (!xpad->idata) {
@@ -251,18 +244,18 @@
                 kfree(xpad);
 		return -ENOMEM;
         }
-	
+
 	ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
-	
+
 	usb_fill_int_urb(xpad->irq_in, udev,
 			 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
 			 xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
 			 xpad, ep_irq_in->bInterval);
 	xpad->irq_in->transfer_dma = xpad->idata_dma;
 	xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-	
+
 	xpad->udev = udev;
-	
+
 	xpad->dev.id.bustype = BUS_USB;
 	xpad->dev.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
 	xpad->dev.id.product = le16_to_cpu(udev->descriptor.idProduct);
@@ -273,21 +266,21 @@
 	xpad->dev.phys = xpad->phys;
 	xpad->dev.open = xpad_open;
 	xpad->dev.close = xpad_close;
-	
+
 	usb_make_path(udev, path, 64);
 	snprintf(xpad->phys, 64,  "%s/input0", path);
-	
+
 	xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	
+
 	for (i = 0; xpad_btn[i] >= 0; i++)
 		set_bit(xpad_btn[i], xpad->dev.keybit);
-	
+
 	for (i = 0; xpad_abs[i] >= 0; i++) {
-		
+
 		signed short t = xpad_abs[i];
-		
+
 		set_bit(t, xpad->dev.absbit);
-		
+
 		switch (t) {
 			case ABS_X:
 			case ABS_Y:
@@ -310,11 +303,11 @@
 				break;
 		}
 	}
-	
+
 	input_register_device(&xpad->dev);
-	
+
 	printk(KERN_INFO "input: %s on %s", xpad->dev.name, path);
-	
+
 	usb_set_intfdata(intf, xpad);
 	return 0;
 }
@@ -322,7 +315,7 @@
 static void xpad_disconnect(struct usb_interface *intf)
 {
 	struct usb_xpad *xpad = usb_get_intfdata (intf);
-	
+
 	usb_set_intfdata(intf, NULL);
 	if (xpad) {
 		usb_kill_urb(xpad->irq_in);
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index d976790..5f4496d 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -1166,7 +1166,7 @@
 		pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
 		if (netif_msg_link(pegasus))
 			pr_info("%s: Promiscuous mode enabled.\n", net->name);
-	} else if ((net->mc_count > multicast_filter_limit) ||
+	} else if (net->mc_count ||
 		   (net->flags & IFF_ALLMULTI)) {
 		pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
 		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index 13ccede..b98f2a8 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -249,6 +249,8 @@
 		DEFAULT_GPIO_RESET)
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 8fb2233..626b016 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -667,7 +667,7 @@
 	if (netdev->flags & IFF_PROMISC) {
 		dev->rx_creg |= cpu_to_le16(0x0001);
 		info("%s: promiscuous mode", netdev->name);
-	} else if ((netdev->mc_count > multicast_filter_limit) ||
+	} else if (netdev->mc_count ||
 		   (netdev->flags & IFF_ALLMULTI)) {
 		dev->rx_creg &= cpu_to_le16(0xfffe);
 		dev->rx_creg |= cpu_to_le16(0x0002);
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 9789115..7bc1d44 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -350,10 +350,8 @@
 static int default_cmode __initdata = CMODE_8;
 #endif
 
-#ifdef CONFIG_PMAC_PBOOK
 static int default_crt_on __initdata = 0;
 static int default_lcd_on __initdata = 1;
-#endif
 
 #ifdef CONFIG_MTRR
 static int mtrr = 1;
@@ -1249,7 +1247,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
 static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
 {
 	if (on) {
@@ -1284,7 +1281,6 @@
 		aty_st_le32(LVDS_GEN_CNTL, reg);
 	}
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
 static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
 {
@@ -1491,12 +1487,10 @@
 	info->fix.visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR
 		: FB_VISUAL_DIRECTCOLOR;
 
-#ifdef CONFIG_PMAC_PBOOK
 	if (par->chip_gen == rage_M3) {
 		aty128_set_crt_enable(par, par->crt_on);
 		aty128_set_lcd_enable(par, par->lcd_on);
 	}
-#endif
 	if (par->accel_flags & FB_ACCELF_TEXT)
 		aty128_init_engine(par);
 
@@ -1652,7 +1646,6 @@
 		return 0;
 
 	while ((this_opt = strsep(&options, ",")) != NULL) {
-#ifdef CONFIG_PMAC_PBOOK
 		if (!strncmp(this_opt, "lcd:", 4)) {
 			default_lcd_on = simple_strtoul(this_opt+4, NULL, 0);
 			continue;
@@ -1660,7 +1653,6 @@
 			default_crt_on = simple_strtoul(this_opt+4, NULL, 0);
 			continue;
 		}
-#endif
 #ifdef CONFIG_MTRR
 		if(!strncmp(this_opt, "nomtrr", 6)) {
 			mtrr = 0;
@@ -1752,10 +1744,8 @@
 	info->fbops = &aty128fb_ops;
 	info->flags = FBINFO_FLAG_DEFAULT;
 
-#ifdef CONFIG_PMAC_PBOOK
 	par->lcd_on = default_lcd_on;
 	par->crt_on = default_crt_on;
-#endif
 
 	var = default_var;
 #ifdef CONFIG_PPC_PMAC
@@ -2035,12 +2025,10 @@
 
 	aty_st_8(CRTC_EXT_CNTL+1, state);
 
-#ifdef CONFIG_PMAC_PBOOK
 	if (par->chip_gen == rage_M3) {
 		aty128_set_crt_enable(par, par->crt_on && !blank);
 		aty128_set_lcd_enable(par, par->lcd_on && !blank);
 	}
-#endif	
 #ifdef CONFIG_PMAC_BACKLIGHT
 	if ((_machine == _MACH_Pmac) && !blank)
 		set_backlight_enable(1);
@@ -2124,7 +2112,6 @@
 static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 			  u_long arg, struct fb_info *info)
 {
-#ifdef CONFIG_PMAC_PBOOK
 	struct aty128fb_par *par = info->par;
 	u32 value;
 	int rc;
@@ -2149,7 +2136,6 @@
 		value = (par->crt_on << 1) | par->lcd_on;
 		return put_user(value, (__u32 __user *)arg);
 	}
-#endif
 	return -EINVAL;
 }
 
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 95e7255..e75a965 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -28,22 +28,17 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/console.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
 
 /*
  * Since we access the display with inb/outb to fixed port numbers,
  * we can only handle one 6555x chip.  -- paulus
  */
-static struct fb_info chipsfb_info;
-
 #define write_ind(num, val, ap, dp)	do { \
 	outb((num), (ap)); outb((val), (dp)); \
 } while (0)
@@ -74,14 +69,6 @@
 	inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \
 } while (0)
 
-#ifdef CONFIG_PMAC_PBOOK
-static unsigned char *save_framebuffer;
-int chips_sleep_notify(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier chips_sleep_notifier = {
-	chips_sleep_notify, SLEEP_LEVEL_VIDEO,
-};
-#endif
-
 /*
  * Exported functions
  */
@@ -356,6 +343,8 @@
 
 static void __init init_chips(struct fb_info *p, unsigned long addr)
 {
+	memset(p->screen_base, 0, 0x100000);
+
 	p->fix = chipsfb_fix;
 	p->fix.smem_start = addr;
 
@@ -366,34 +355,41 @@
 
 	fb_alloc_cmap(&p->cmap, 256, 0);
 
-	if (register_framebuffer(p) < 0) {
-		printk(KERN_ERR "C&T 65550 framebuffer failed to register\n");
-		return;
-	}
-
-	printk(KERN_INFO "fb%d: Chips 65550 frame buffer (%dK RAM detected)\n",
-		p->node, p->fix.smem_len / 1024);
-
 	chips_hw_init();
 }
 
 static int __devinit
 chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
 {
-	struct fb_info *p = &chipsfb_info;
+	struct fb_info *p;
 	unsigned long addr, size;
 	unsigned short cmd;
+	int rc = -ENODEV;
+
+	if (pci_enable_device(dp) < 0) {
+		dev_err(&dp->dev, "Cannot enable PCI device\n");
+		goto err_out;
+	}
 
 	if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
-		return -ENODEV;
+		goto err_disable;
 	addr = pci_resource_start(dp, 0);
 	size = pci_resource_len(dp, 0);
 	if (addr == 0)
-		return -ENODEV;
-	if (p->screen_base != 0)
-		return -EBUSY;
-	if (!request_mem_region(addr, size, "chipsfb"))
-		return -EBUSY;
+		goto err_disable;
+
+	p = framebuffer_alloc(0, &dp->dev);
+	if (p == NULL) {
+		dev_err(&dp->dev, "Cannot allocate framebuffer structure\n");
+		rc = -ENOMEM;
+		goto err_disable;
+	}
+
+	if (pci_request_region(dp, 0, "chipsfb") != 0) {
+		dev_err(&dp->dev, "Cannot request framebuffer\n");
+		rc = -EBUSY;
+		goto err_release_fb;
+	}
 
 #ifdef __BIG_ENDIAN
 	addr += 0x800000;	// Use big-endian aperture
@@ -411,38 +407,90 @@
 	set_backlight_enable(1);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
+#ifdef CONFIG_PPC
 	p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE);
+#else
+	p->screen_base = ioremap(addr, 0x200000);
+#endif
 	if (p->screen_base == NULL) {
-		release_mem_region(addr, size);
-		return -ENOMEM;
+		dev_err(&dp->dev, "Cannot map framebuffer\n");
+		rc = -ENOMEM;
+		goto err_release_pci;
 	}
-	p->device = &dp->dev;
-	init_chips(p, addr);
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier(&chips_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
 
 	pci_set_drvdata(dp, p);
+	p->device = &dp->dev;
+
+	init_chips(p, addr);
+
+	if (register_framebuffer(p) < 0) {
+		dev_err(&dp->dev,"C&T 65550 framebuffer failed to register\n");
+		goto err_unmap;
+	}
+
+	dev_info(&dp->dev,"fb%d: Chips 65550 frame buffer"
+		 " (%dK RAM detected)\n",
+		 p->node, p->fix.smem_len / 1024);
+
 	return 0;
+
+ err_unmap:
+	iounmap(p->screen_base);
+ err_release_pci:
+	pci_release_region(dp, 0);
+ err_release_fb:
+	framebuffer_release(p);
+ err_disable:
+ err_out:
+	return rc;
 }
 
 static void __devexit chipsfb_remove(struct pci_dev *dp)
 {
 	struct fb_info *p = pci_get_drvdata(dp);
 
-	if (p != &chipsfb_info || p->screen_base == NULL)
+	if (p->screen_base == NULL)
 		return;
 	unregister_framebuffer(p);
 	iounmap(p->screen_base);
 	p->screen_base = NULL;
-	release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_unregister_sleep_notifier(&chips_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+	pci_release_region(dp, 0);
 }
 
+#ifdef CONFIG_PM
+static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+        struct fb_info *p = pci_get_drvdata(pdev);
+
+	if (state == pdev->dev.power.power_state)
+		return 0;
+	if (state != PM_SUSPEND_MEM)
+		goto done;
+
+	acquire_console_sem();
+	chipsfb_blank(1, p);
+	fb_set_suspend(p, 1);
+	release_console_sem();
+ done:
+	pdev->dev.power.power_state = state;
+	return 0;
+}
+
+static int chipsfb_pci_resume(struct pci_dev *pdev)
+{
+        struct fb_info *p = pci_get_drvdata(pdev);
+
+	acquire_console_sem();
+	fb_set_suspend(p, 0);
+	chipsfb_blank(0, p);
+	release_console_sem();
+
+	pdev->dev.power.power_state = PMSG_ON;
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+
 static struct pci_device_id chipsfb_pci_tbl[] = {
 	{ PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_65550, PCI_ANY_ID, PCI_ANY_ID },
 	{ 0 }
@@ -455,6 +503,10 @@
 	.id_table =	chipsfb_pci_tbl,
 	.probe =	chipsfb_pci_init,
 	.remove =	__devexit_p(chipsfb_remove),
+#ifdef CONFIG_PM
+	.suspend =	chipsfb_pci_suspend,
+	.resume =	chipsfb_pci_resume,
+#endif
 };
 
 int __init chips_init(void)
@@ -472,48 +524,4 @@
 	pci_unregister_driver(&chipsfb_driver);
 }
 
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-int
-chips_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-	struct fb_info *p = &chipsfb_info;
-	int nb = p->var.yres * p->fix.line_length;
-
-	if (p->screen_base == NULL)
-		return PBOOK_SLEEP_OK;
-
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		save_framebuffer = vmalloc(nb);
-		if (save_framebuffer == NULL)
-			return PBOOK_SLEEP_REFUSE;
-		break;
-	case PBOOK_SLEEP_REJECT:
-		if (save_framebuffer) {
-			vfree(save_framebuffer);
-			save_framebuffer = NULL;
-		}
-		break;
-	case PBOOK_SLEEP_NOW:
-		chipsfb_blank(1, p);
-		if (save_framebuffer)
-			memcpy(save_framebuffer, p->screen_base, nb);
-		break;
-	case PBOOK_WAKE:
-		if (save_framebuffer) {
-			memcpy(p->screen_base, save_framebuffer, nb);
-			vfree(save_framebuffer);
-			save_framebuffer = NULL;
-		}
-		chipsfb_blank(0, p);
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
 MODULE_LICENSE("GPL");
diff --git a/fs/Makefile b/fs/Makefile
index fc92e59..20edcf28 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -10,6 +10,7 @@
 		ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
 		attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
 		seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
+		ioprio.o
 
 obj-$(CONFIG_EPOLL)		+= eventpoll.o
 obj-$(CONFIG_COMPAT)		+= compat.o
diff --git a/fs/ioprio.c b/fs/ioprio.c
new file mode 100644
index 0000000..663e420
--- /dev/null
+++ b/fs/ioprio.c
@@ -0,0 +1,172 @@
+/*
+ * fs/ioprio.c
+ *
+ * Copyright (C) 2004 Jens Axboe <axboe@suse.de>
+ *
+ * Helper functions for setting/querying io priorities of processes. The
+ * system calls closely mimmick getpriority/setpriority, see the man page for
+ * those. The prio argument is a composite of prio class and prio data, where
+ * the data argument has meaning within that class. The standard scheduling
+ * classes have 8 distinct prio levels, with 0 being the highest prio and 7
+ * being the lowest.
+ *
+ * IOW, setting BE scheduling class with prio 2 is done ala:
+ *
+ * unsigned int prio = (IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT) | 2;
+ *
+ * ioprio_set(PRIO_PROCESS, pid, prio);
+ *
+ * See also Documentation/block/ioprio.txt
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ioprio.h>
+#include <linux/blkdev.h>
+
+static int set_task_ioprio(struct task_struct *task, int ioprio)
+{
+	struct io_context *ioc;
+
+	if (task->uid != current->euid &&
+	    task->uid != current->uid && !capable(CAP_SYS_NICE))
+		return -EPERM;
+
+	task_lock(task);
+
+	task->ioprio = ioprio;
+
+	ioc = task->io_context;
+	if (ioc && ioc->set_ioprio)
+		ioc->set_ioprio(ioc, ioprio);
+
+	task_unlock(task);
+	return 0;
+}
+
+asmlinkage int sys_ioprio_set(int which, int who, int ioprio)
+{
+	int class = IOPRIO_PRIO_CLASS(ioprio);
+	int data = IOPRIO_PRIO_DATA(ioprio);
+	struct task_struct *p, *g;
+	struct user_struct *user;
+	int ret;
+
+	switch (class) {
+		case IOPRIO_CLASS_RT:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+			/* fall through, rt has prio field too */
+		case IOPRIO_CLASS_BE:
+			if (data >= IOPRIO_BE_NR || data < 0)
+				return -EINVAL;
+
+			break;
+		case IOPRIO_CLASS_IDLE:
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	ret = -ESRCH;
+	read_lock_irq(&tasklist_lock);
+	switch (which) {
+		case IOPRIO_WHO_PROCESS:
+			if (!who)
+				p = current;
+			else
+				p = find_task_by_pid(who);
+			if (p)
+				ret = set_task_ioprio(p, ioprio);
+			break;
+		case IOPRIO_WHO_PGRP:
+			if (!who)
+				who = process_group(current);
+			do_each_task_pid(who, PIDTYPE_PGID, p) {
+				ret = set_task_ioprio(p, ioprio);
+				if (ret)
+					break;
+			} while_each_task_pid(who, PIDTYPE_PGID, p);
+			break;
+		case IOPRIO_WHO_USER:
+			if (!who)
+				user = current->user;
+			else
+				user = find_user(who);
+
+			if (!user)
+				break;
+
+			do_each_thread(g, p) {
+				if (p->uid != who)
+					continue;
+				ret = set_task_ioprio(p, ioprio);
+				if (ret)
+					break;
+			} while_each_thread(g, p);
+
+			if (who)
+				free_uid(user);
+			break;
+		default:
+			ret = -EINVAL;
+	}
+
+	read_unlock_irq(&tasklist_lock);
+	return ret;
+}
+
+asmlinkage int sys_ioprio_get(int which, int who)
+{
+	struct task_struct *g, *p;
+	struct user_struct *user;
+	int ret = -ESRCH;
+
+	read_lock_irq(&tasklist_lock);
+	switch (which) {
+		case IOPRIO_WHO_PROCESS:
+			if (!who)
+				p = current;
+			else
+				p = find_task_by_pid(who);
+			if (p)
+				ret = p->ioprio;
+			break;
+		case IOPRIO_WHO_PGRP:
+			if (!who)
+				who = process_group(current);
+			do_each_task_pid(who, PIDTYPE_PGID, p) {
+				if (ret == -ESRCH)
+					ret = p->ioprio;
+				else
+					ret = ioprio_best(ret, p->ioprio);
+			} while_each_task_pid(who, PIDTYPE_PGID, p);
+			break;
+		case IOPRIO_WHO_USER:
+			if (!who)
+				user = current->user;
+			else
+				user = find_user(who);
+
+			if (!user)
+				break;
+
+			do_each_thread(g, p) {
+				if (p->uid != user->uid)
+					continue;
+				if (ret == -ESRCH)
+					ret = p->ioprio;
+				else
+					ret = ioprio_best(ret, p->ioprio);
+			} while_each_thread(g, p);
+
+			if (who)
+				free_uid(user);
+			break;
+		default:
+			ret = -EINVAL;
+	}
+
+	read_unlock_irq(&tasklist_lock);
+	return ret;
+}
+
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 7b87707..d1bcf0d 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -645,18 +645,22 @@
 
 static void write_chunk(struct buffer_chunk *chunk) {
     int i;
+    get_fs_excl();
     for (i = 0; i < chunk->nr ; i++) {
 	submit_logged_buffer(chunk->bh[i]) ;
     }
     chunk->nr = 0;
+    put_fs_excl();
 }
 
 static void write_ordered_chunk(struct buffer_chunk *chunk) {
     int i;
+    get_fs_excl();
     for (i = 0; i < chunk->nr ; i++) {
 	submit_ordered_buffer(chunk->bh[i]) ;
     }
     chunk->nr = 0;
+    put_fs_excl();
 }
 
 static int add_to_chunk(struct buffer_chunk *chunk, struct buffer_head *bh,
@@ -918,6 +922,8 @@
     return 0 ;
   }
 
+  get_fs_excl();
+
   /* before we can put our commit blocks on disk, we have to make sure everyone older than
   ** us is on disk too
   */
@@ -1055,6 +1061,7 @@
 
   if (retval)
     reiserfs_abort (s, retval, "Journal write error in %s", __FUNCTION__);
+  put_fs_excl();
   return retval;
 }
 
@@ -1251,6 +1258,8 @@
     return 0 ;
   }
 
+  get_fs_excl();
+
   /* if all the work is already done, get out of here */
   if (atomic_read(&(jl->j_nonzerolen)) <= 0 && 
       atomic_read(&(jl->j_commit_left)) <= 0) {
@@ -1450,6 +1459,7 @@
   put_journal_list(s, jl);
   if (flushall)
     up(&journal->j_flush_sem);
+  put_fs_excl();
   return err ;
 } 
 
@@ -2719,6 +2729,7 @@
   th->t_trans_id = journal->j_trans_id ;
   unlock_journal(p_s_sb) ;
   INIT_LIST_HEAD (&th->t_list);
+  get_fs_excl();
   return 0 ;
 
 out_fail:
@@ -3526,6 +3537,7 @@
   BUG_ON (th->t_refcount > 1);
   BUG_ON (!th->t_trans_id);
 
+  put_fs_excl();
   current->journal_info = th->t_handle_save;
   reiserfs_check_lock_depth(p_s_sb, "journal end");
   if (journal->j_len == 0) {
diff --git a/include/asm-arm/arch-ixp4xx/debug-macro.S b/include/asm-arm/arch-ixp4xx/debug-macro.S
index 45a6c6c..2e23651 100644
--- a/include/asm-arm/arch-ixp4xx/debug-macro.S
+++ b/include/asm-arm/arch-ixp4xx/debug-macro.S
@@ -14,8 +14,8 @@
                 mrc     p15, 0, \rx, c1, c0
                 tst     \rx, #1                 @ MMU enabled?
                 moveq   \rx, #0xc8000000
-		orrne	\rx, \rx, #0x00b00000
                 movne   \rx, #0xff000000
+		orrne	\rx, \rx, #0x00b00000
                 add     \rx,\rx,#3              @ Uart regs are at off set of 3 if
 						@ byte writes used - Big Endian.
                 .endm
diff --git a/include/asm-arm/ide.h b/include/asm-arm/ide.h
index 2114acb..4f68c8a 100644
--- a/include/asm-arm/ide.h
+++ b/include/asm-arm/ide.h
@@ -5,7 +5,7 @@
  */
 
 /*
- *  This file contains the i386 architecture specific IDE code.
+ *  This file contains the ARM architecture specific IDE code.
  */
 
 #ifndef __ASMARM_IDE_H
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index cc4b5f5..cfa71a0 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -82,7 +82,7 @@
  * only.  Their primary purpose is to access PCI and ISA peripherals.
  *
  * Note that for a big endian machine, this implies that the following
- * big endian mode connectivity is in place, as described by numerious
+ * big endian mode connectivity is in place, as described by numerous
  * ARM documents:
  *
  *    PCI:  D0-D7   D8-D15 D16-D23 D24-D31
diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h
index 047980a..2cf279a 100644
--- a/include/asm-arm/mach/time.h
+++ b/include/asm-arm/mach/time.h
@@ -60,6 +60,8 @@
 };
 
 void timer_dyn_reprogram(void);
+#else
+#define timer_dyn_reprogram()	do { } while (0)
 #endif
 
 extern struct sys_timer *system_timer;
diff --git a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h
index f22fab0..ab216e1 100644
--- a/include/asm-i386/tlbflush.h
+++ b/include/asm-i386/tlbflush.h
@@ -22,16 +22,18 @@
  */
 #define __flush_tlb_global()						\
 	do {								\
-		unsigned int tmpreg;					\
+		unsigned int tmpreg, cr4, cr4_orig;			\
 									\
 		__asm__ __volatile__(					\
-			"movl %1, %%cr4;  # turn off PGE     \n"	\
+			"movl %%cr4, %2;  # turn off PGE     \n"	\
+			"movl %2, %1;                        \n"	\
+			"andl %3, %1;                        \n"	\
+			"movl %1, %%cr4;                     \n"	\
 			"movl %%cr3, %0;                     \n"	\
 			"movl %0, %%cr3;  # flush TLB        \n"	\
 			"movl %2, %%cr4;  # turn PGE back on \n"	\
-			: "=&r" (tmpreg)				\
-			: "r" (mmu_cr4_features & ~X86_CR4_PGE),	\
-			  "r" (mmu_cr4_features)			\
+			: "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig)	\
+			: "i" (~X86_CR4_PGE)				\
 			: "memory");					\
 	} while (0)
 
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 176413f..e25e4c7 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -294,8 +294,10 @@
 #define __NR_add_key		286
 #define __NR_request_key	287
 #define __NR_keyctl		288
+#define __NR_ioprio_set		289
+#define __NR_ioprio_get		290
 
-#define NR_syscalls 289
+#define NR_syscalls 291
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index f7f43ec..517f164 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -263,6 +263,8 @@
 #define __NR_add_key			1271
 #define __NR_request_key		1272
 #define __NR_keyctl			1273
+#define __NR_ioprio_set			1274
+#define __NR_ioprio_get			1275
 #define __NR_set_zone_reclaim		1276
 
 #ifdef __KERNEL__
diff --git a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
index dbe8533..7848aa6 100644
--- a/include/asm-ppc/open_pic.h
+++ b/include/asm-ppc/open_pic.h
@@ -25,6 +25,11 @@
 #define OPENPIC_VEC_IPI		118	/* and up */
 #define OPENPIC_VEC_SPURIOUS	255
 
+/* Priorities */
+#define OPENPIC_PRIORITY_IPI_BASE	10
+#define OPENPIC_PRIORITY_DEFAULT	4
+#define OPENPIC_PRIORITY_NMI		9
+
 /* OpenPIC IRQ controller structure */
 extern struct hw_interrupt_type open_pic;
 
@@ -42,6 +47,7 @@
 extern void openpic_set_sources(int first_irq, int num_irqs, void __iomem *isr);
 extern void openpic_init(int linux_irq_offset);
 extern void openpic_init_nmi_irq(u_int irq);
+extern void openpic_set_irq_priority(u_int irq, u_int pri);
 extern void openpic_hookup_cascade(u_int irq, char *name,
 				   int (*cascade_fn)(struct pt_regs *));
 extern u_int openpic_irq(void);
diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
index cc51e5c..e8b7922 100644
--- a/include/asm-ppc/unistd.h
+++ b/include/asm-ppc/unistd.h
@@ -277,8 +277,10 @@
 #define __NR_request_key	270
 #define __NR_keyctl		271
 #define __NR_waitid		272
+#define __NR_ioprio_set		273
+#define __NR_ioprio_get		274
 
-#define __NR_syscalls		273
+#define __NR_syscalls		275
 
 #define __NR(n)	#n
 
diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h
index 2e811ac..0617423 100644
--- a/include/asm-x86_64/tlbflush.h
+++ b/include/asm-x86_64/tlbflush.h
@@ -22,16 +22,18 @@
  */
 #define __flush_tlb_global()						\
 	do {								\
-		unsigned long tmpreg;					\
+		unsigned long tmpreg, cr4, cr4_orig;			\
 									\
 		__asm__ __volatile__(					\
-			"movq %1, %%cr4;  # turn off PGE     \n"	\
+			"movq %%cr4, %2;  # turn off PGE     \n"	\
+			"movq %2, %1;                        \n"	\
+			"andq %3, %1;                        \n"	\
+			"movq %1, %%cr4;                     \n"	\
 			"movq %%cr3, %0;  # flush TLB        \n"	\
 			"movq %0, %%cr3;                     \n"	\
 			"movq %2, %%cr4;  # turn PGE back on \n"	\
-			: "=&r" (tmpreg)				\
-			: "r" (mmu_cr4_features & ~X86_CR4_PGE),	\
-			  "r" (mmu_cr4_features)			\
+			: "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig)	\
+			: "i" (~X86_CR4_PGE)				\
 			: "memory");					\
 	} while (0)
 
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index d767adc..6560439 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -561,8 +561,12 @@
 __SYSCALL(__NR_request_key, sys_request_key)
 #define __NR_keyctl		250
 __SYSCALL(__NR_keyctl, sys_keyctl)
+#define __NR_ioprio_set		251
+__SYSCALL(__NR_ioprio_set, sys_ioprio_set)
+#define __NR_ioprio_get		252
+__SYSCALL(__NR_ioprio_get, sys_ioprio_get)
 
-#define __NR_syscall_max __NR_keyctl
+#define __NR_syscall_max __NR_ioprio_get
 #ifndef __NO_STUBS
 
 /* user-visible error numbers are in the range -1 - -4095 */
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 0380227..36ef29f 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -22,6 +22,7 @@
 
 #include <linux/highmem.h>
 #include <linux/mempool.h>
+#include <linux/ioprio.h>
 
 /* Platforms may set this to teach the BIO layer about IOMMU hardware. */
 #include <asm/io.h>
@@ -150,6 +151,19 @@
 #define BIO_RW_SYNC	4
 
 /*
+ * upper 16 bits of bi_rw define the io priority of this bio
+ */
+#define BIO_PRIO_SHIFT	(8 * sizeof(unsigned long) - IOPRIO_BITS)
+#define bio_prio(bio)	((bio)->bi_rw >> BIO_PRIO_SHIFT)
+#define bio_prio_valid(bio)	ioprio_valid(bio_prio(bio))
+
+#define bio_set_prio(bio, prio)		do {			\
+	WARN_ON(prio >= (1 << IOPRIO_BITS));			\
+	(bio)->bi_rw &= ((1UL << BIO_PRIO_SHIFT) - 1);		\
+	(bio)->bi_rw |= ((unsigned long) (prio) << BIO_PRIO_SHIFT);	\
+} while (0)
+
+/*
  * various member access, note that bio_data should of course not be used
  * on highmem page vectors
  */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index b54a034..21a8674 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -54,16 +54,23 @@
 
 struct cfq_queue;
 struct cfq_io_context {
-	void (*dtor)(struct cfq_io_context *);
-	void (*exit)(struct cfq_io_context *);
-
-	struct io_context *ioc;
-
 	/*
 	 * circular list of cfq_io_contexts belonging to a process io context
 	 */
 	struct list_head list;
 	struct cfq_queue *cfqq;
+	void *key;
+
+	struct io_context *ioc;
+
+	unsigned long last_end_request;
+	unsigned long last_queue;
+	unsigned long ttime_total;
+	unsigned long ttime_samples;
+	unsigned long ttime_mean;
+
+	void (*dtor)(struct cfq_io_context *);
+	void (*exit)(struct cfq_io_context *);
 };
 
 /*
@@ -73,7 +80,9 @@
  */
 struct io_context {
 	atomic_t refcount;
-	pid_t pid;
+	struct task_struct *task;
+
+	int (*set_ioprio)(struct io_context *, unsigned int);
 
 	/*
 	 * For request batching
@@ -81,8 +90,6 @@
 	unsigned long last_waited; /* Time last woken after wait for request */
 	int nr_batch_requests;     /* Number of requests left in the batch */
 
-	spinlock_t lock;
-
 	struct as_io_context *aic;
 	struct cfq_io_context *cic;
 };
@@ -134,6 +141,8 @@
 
 	void *elevator_private;
 
+	unsigned short ioprio;
+
 	int rq_status;	/* should split this into a few status bits */
 	struct gendisk *rq_disk;
 	int errors;
diff --git a/include/linux/cciss_ioctl.h b/include/linux/cciss_ioctl.h
index ee0c6e8..424d5e6 100644
--- a/include/linux/cciss_ioctl.h
+++ b/include/linux/cciss_ioctl.h
@@ -10,6 +10,7 @@
 typedef struct _cciss_pci_info_struct
 {
 	unsigned char 	bus;
+	unsigned short	domain;
 	unsigned char 	dev_fn;
 	__u32 		board_id;
 } cciss_pci_info_struct; 
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index ee54f81..ea6bbc2 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -16,9 +16,9 @@
 typedef void (elevator_requeue_req_fn) (request_queue_t *, struct request *);
 typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *);
 typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *);
-typedef int (elevator_may_queue_fn) (request_queue_t *, int);
+typedef int (elevator_may_queue_fn) (request_queue_t *, int, struct bio *);
 
-typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int);
+typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, int);
 typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
 typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *);
 
@@ -96,9 +96,9 @@
 extern struct request *elv_latter_request(request_queue_t *, struct request *);
 extern int elv_register_queue(request_queue_t *q);
 extern void elv_unregister_queue(request_queue_t *q);
-extern int elv_may_queue(request_queue_t *, int);
+extern int elv_may_queue(request_queue_t *, int, struct bio *);
 extern void elv_completed_request(request_queue_t *, struct request *);
-extern int elv_set_request(request_queue_t *, struct request *, int);
+extern int elv_set_request(request_queue_t *, struct request *, struct bio *, int);
 extern void elv_put_request(request_queue_t *, struct request *);
 
 /*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3ae8e37..047bde3 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -213,6 +213,7 @@
 #include <linux/radix-tree.h>
 #include <linux/prio_tree.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
@@ -822,16 +823,34 @@
 #define vfs_check_frozen(sb, level) \
 	wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level)))
 
+static inline void get_fs_excl(void)
+{
+	atomic_inc(&current->fs_excl);
+}
+
+static inline void put_fs_excl(void)
+{
+	atomic_dec(&current->fs_excl);
+}
+
+static inline int has_fs_excl(void)
+{
+	return atomic_read(&current->fs_excl);
+}
+
+
 /*
  * Superblock locking.
  */
 static inline void lock_super(struct super_block * sb)
 {
+	get_fs_excl();
 	down(&sb->s_lock);
 }
 
 static inline void unlock_super(struct super_block * sb)
 {
+	put_fs_excl();
 	up(&sb->s_lock);
 }
 
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 03206a4..c727c195 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -81,6 +81,7 @@
 	.mm		= NULL,						\
 	.active_mm	= &init_mm,					\
 	.run_list	= LIST_HEAD_INIT(tsk.run_list),			\
+	.ioprio		= 0,						\
 	.time_slice	= HZ,						\
 	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
 	.ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),		\
@@ -110,6 +111,7 @@
 	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
 	.cpu_timers	= INIT_CPU_TIMERS(tsk.cpu_timers),		\
+	.fs_excl	= ATOMIC_INIT(0),				\
 }
 
 
diff --git a/include/linux/input.h b/include/linux/input.h
index 9d9598e..b9cc0ac 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -859,6 +859,10 @@
 	int (*erase_effect)(struct input_dev *dev, int effect_id);
 
 	struct input_handle *grab;
+
+	struct semaphore sem;	/* serializes open and close operations */
+	unsigned int users;
+
 	struct device *dev;
 
 	struct list_head	h_list;
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
new file mode 100644
index 0000000..8a453a0
--- /dev/null
+++ b/include/linux/ioprio.h
@@ -0,0 +1,88 @@
+#ifndef IOPRIO_H
+#define IOPRIO_H
+
+#include <linux/sched.h>
+
+/*
+ * Gives us 8 prio classes with 13-bits of data for each class
+ */
+#define IOPRIO_BITS		(16)
+#define IOPRIO_CLASS_SHIFT	(13)
+#define IOPRIO_PRIO_MASK	((1UL << IOPRIO_CLASS_SHIFT) - 1)
+
+#define IOPRIO_PRIO_CLASS(mask)	((mask) >> IOPRIO_CLASS_SHIFT)
+#define IOPRIO_PRIO_DATA(mask)	((mask) & IOPRIO_PRIO_MASK)
+#define IOPRIO_PRIO_VALUE(class, data)	(((class) << IOPRIO_CLASS_SHIFT) | data)
+
+#define ioprio_valid(mask)	(IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE)
+
+/*
+ * These are the io priority groups as implemented by CFQ. RT is the realtime
+ * class, it always gets premium service. BE is the best-effort scheduling
+ * class, the default for any process. IDLE is the idle scheduling class, it
+ * is only served when no one else is using the disk.
+ */
+enum {
+	IOPRIO_CLASS_NONE,
+	IOPRIO_CLASS_RT,
+	IOPRIO_CLASS_BE,
+	IOPRIO_CLASS_IDLE,
+};
+
+/*
+ * 8 best effort priority levels are supported
+ */
+#define IOPRIO_BE_NR	(8)
+
+asmlinkage int sys_ioprio_set(int, int, int);
+asmlinkage int sys_ioprio_get(int, int);
+
+enum {
+	IOPRIO_WHO_PROCESS = 1,
+	IOPRIO_WHO_PGRP,
+	IOPRIO_WHO_USER,
+};
+
+/*
+ * if process has set io priority explicitly, use that. if not, convert
+ * the cpu scheduler nice value to an io priority
+ */
+#define IOPRIO_NORM	(4)
+static inline int task_ioprio(struct task_struct *task)
+{
+	WARN_ON(!ioprio_valid(task->ioprio));
+	return IOPRIO_PRIO_DATA(task->ioprio);
+}
+
+static inline int task_nice_ioprio(struct task_struct *task)
+{
+	return (task_nice(task) + 20) / 5;
+}
+
+/*
+ * For inheritance, return the highest of the two given priorities
+ */
+static inline int ioprio_best(unsigned short aprio, unsigned short bprio)
+{
+	unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
+	unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
+
+	if (!ioprio_valid(aprio))
+		return bprio;
+	if (!ioprio_valid(bprio))
+		return aprio;
+
+	if (aclass == IOPRIO_CLASS_NONE)
+		aclass = IOPRIO_CLASS_BE;
+	if (bclass == IOPRIO_CLASS_NONE)
+		bclass = IOPRIO_CLASS_BE;
+
+	if (aclass == bclass)
+		return min(aprio, bprio);
+	if (aclass > bclass)
+		return bprio;
+	else
+		return aprio;
+}
+
+#endif
diff --git a/include/linux/joystick.h b/include/linux/joystick.h
index b7e0ab6..06b9af7 100644
--- a/include/linux/joystick.h
+++ b/include/linux/joystick.h
@@ -111,18 +111,35 @@
 #define JS_SET_ALL		8
 
 struct JS_DATA_TYPE {
-	int buttons;
-	int x;
-	int y;
+	__s32 buttons;
+	__s32 x;
+	__s32 y;
 };
 
-struct JS_DATA_SAVE_TYPE {
-	int JS_TIMEOUT;
-	int BUSY;
-	long JS_EXPIRETIME;
-	long JS_TIMELIMIT;
+struct JS_DATA_SAVE_TYPE_32 {
+	__s32 JS_TIMEOUT;
+	__s32 BUSY;
+	__s32 JS_EXPIRETIME;
+	__s32 JS_TIMELIMIT;
 	struct JS_DATA_TYPE JS_SAVE;
 	struct JS_DATA_TYPE JS_CORR;
 };
 
+struct JS_DATA_SAVE_TYPE_64 {
+	__s32 JS_TIMEOUT;
+	__s32 BUSY;
+	__s64 JS_EXPIRETIME;
+	__s64 JS_TIMELIMIT;
+	struct JS_DATA_TYPE JS_SAVE;
+	struct JS_DATA_TYPE JS_CORR;
+};
+
+#if BITS_PER_LONG == 64
+#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_64
+#elif BITS_PER_LONG == 32
+#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_32
+#else
+#error Unexpected BITS_PER_LONG
+#endif
+
 #endif /* _LINUX_JOYSTICK_H */
diff --git a/include/linux/libps2.h b/include/linux/libps2.h
index 923bdbc..a710bdd 100644
--- a/include/linux/libps2.h
+++ b/include/linux/libps2.h
@@ -41,6 +41,7 @@
 
 void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
 int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
 int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
 int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command);
 int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index bf60880..a3961e1 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -712,8 +712,9 @@
 #define PCI_DEVICE_ID_HP_DIVA_AUX	0x1290
 #define PCI_DEVICE_ID_HP_DIVA_RMP3	0x1301
 #define PCI_DEVICE_ID_HP_CISSA		0x3220
-#define PCI_DEVICE_ID_HP_CISSB		0x3230
+#define PCI_DEVICE_ID_HP_CISSB		0x3222
 #define PCI_DEVICE_ID_HP_ZX2_IOC	0x4031
+#define PCI_DEVICE_ID_HP_CISSC		0x3230
 
 #define PCI_VENDOR_ID_PCTECH		0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
@@ -1284,6 +1285,8 @@
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2    0x0348
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000       0x034C
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100         0x034E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_14              0x0372
+#define PCI_DEVICE_ID_NVIDIA_NVENET_15              0x0373
 
 #define PCI_VENDOR_ID_IMS		0x10e0
 #define PCI_DEVICE_ID_IMS_8849		0x8849
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 6d73ead..373bd3b 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -166,7 +166,7 @@
 extern int pmu_i2c_simple_write(int bus, int addr,  u8* data, int len);
 
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * Stuff for putting the powerbook to sleep and waking it again.
  *
@@ -208,6 +208,8 @@
 int pmu_register_sleep_notifier(struct pmu_sleep_notifier* notifier);
 int pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* notifier);
 
+#endif /* CONFIG_PM */
+
 #define PMU_MAX_BATTERIES	2
 
 /* values for pmu_power_flags */
@@ -235,6 +237,4 @@
 extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
 extern unsigned int pmu_power_flags;
 
-#endif /* CONFIG_PMAC_PBOOK */
-
 #endif	/* __KERNEL__ */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9530b19..ff48815 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -608,6 +608,8 @@
 	struct list_head run_list;
 	prio_array_t *array;
 
+	unsigned short ioprio;
+
 	unsigned long sleep_avg;
 	unsigned long long timestamp, last_ran;
 	unsigned long long sched_time; /* sched_clock time spent running */
@@ -763,6 +765,7 @@
 	nodemask_t mems_allowed;
 	int cpuset_mems_generation;
 #endif
+	atomic_t fs_excl;	/* holding fs exclusive resources */
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
@@ -1112,7 +1115,8 @@
 
 /*
  * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm, keyring
- * subscriptions and synchronises with wait4().  Also used in procfs.
+ * subscriptions and synchronises with wait4().  Also used in procfs.  Also
+ * pins the final release of task.io_context.
  *
  * Nests both inside and outside of read_lock(&tasklist_lock).
  * It must not be nested with write_lock_irq(&tasklist_lock),
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index 3a2702b..dc89116 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -19,6 +19,11 @@
 		__secure_computing(this_syscall);
 }
 
+static inline int has_secure_computing(struct thread_info *ti)
+{
+	return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP));
+}
+
 #else /* CONFIG_SECCOMP */
 
 #if (__GNUC__ > 2)
@@ -28,6 +33,11 @@
 #endif
 
 #define secure_computing(x) do { } while (0)
+/* static inline to preserve typechecking */
+static inline int has_secure_computing(struct thread_info *ti)
+{
+	return 0;
+}
 
 #endif /* CONFIG_SECCOMP */
 
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 823181a..3e3c1fa 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -22,6 +22,7 @@
 	unsigned int	uartclk;	/* UART clock rate */
 	unsigned char	regshift;	/* register shift */
 	unsigned char	iotype;		/* UPIO_* */
+	unsigned char	hub6;
 	unsigned int	flags;		/* UPF_* flags */
 };
 
diff --git a/include/linux/serio.h b/include/linux/serio.h
index a2d3b9a..aa4d649 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -83,6 +83,7 @@
 }
 
 void serio_unregister_port(struct serio *serio);
+void serio_unregister_child_port(struct serio *serio);
 void __serio_unregister_port_delayed(struct serio *serio, struct module *owner);
 static inline void serio_unregister_port_delayed(struct serio *serio)
 {
@@ -153,6 +154,11 @@
 	return down_interruptible(&serio->drv_sem);
 }
 
+static inline void serio_pin_driver_uninterruptible(struct serio *serio)
+{
+	down(&serio->drv_sem);
+}
+
 static inline void serio_unpin_driver(struct serio *serio)
 {
 	up(&serio->drv_sem);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 1262cb4..d5c3fe1 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -14,11 +14,13 @@
  * Yes, writeback.h requires sched.h
  * No, sched.h is not included from here.
  */
-static inline int current_is_pdflush(void)
+static inline int task_is_pdflush(struct task_struct *task)
 {
-	return current->flags & PF_FLUSHER;
+	return task->flags & PF_FLUSHER;
 }
 
+#define current_is_pdflush()	task_is_pdflush(current)
+
 /*
  * fs/fs-writeback.c
  */
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
new file mode 100644
index 0000000..7fe57f9
--- /dev/null
+++ b/include/net/ieee80211.h
@@ -0,0 +1,882 @@
+/*
+ * Merged with mainline ieee80211.h in Aug 2004.  Original ieee802_11
+ * remains copyright by the original authors
+ *
+ * Portions of the merged code are based on Host AP (software wireless
+ * LAN access point) driver for Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * Adaption to a generic IEEE 802.11 stack by James Ketrenos
+ * <jketreno@linux.intel.com>
+ * Copyright (c) 2004, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+#ifndef IEEE80211_H
+#define IEEE80211_H
+
+#include <linux/if_ether.h> /* ETH_ALEN */
+#include <linux/kernel.h>   /* ARRAY_SIZE */
+
+#if WIRELESS_EXT < 17
+#define IW_QUAL_QUAL_INVALID   0x10
+#define IW_QUAL_LEVEL_INVALID  0x20
+#define IW_QUAL_NOISE_INVALID  0x40
+#define IW_QUAL_QUAL_UPDATED   0x1
+#define IW_QUAL_LEVEL_UPDATED  0x2
+#define IW_QUAL_NOISE_UPDATED  0x4
+#endif
+
+#define IEEE80211_DATA_LEN		2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+   6.2.1.1.2.
+
+   The figure in section 7.1.2 suggests a body size of up to 2312
+   bytes is allowed, which is a bit confusing, I suspect this
+   represents the 2304 bytes of real data, plus a possible 8 bytes of
+   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+
+#define IEEE80211_HLEN			30
+#define IEEE80211_FRAME_LEN		(IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct ieee80211_hdr {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct ieee80211_hdr_3addr {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+} __attribute__ ((packed));
+
+enum eap_type {
+	EAP_PACKET = 0,
+	EAPOL_START,
+	EAPOL_LOGOFF,
+	EAPOL_KEY,
+	EAPOL_ENCAP_ASF_ALERT
+};
+
+static const char *eap_types[] = {
+	[EAP_PACKET]		= "EAP-Packet",
+	[EAPOL_START]		= "EAPOL-Start",
+	[EAPOL_LOGOFF]		= "EAPOL-Logoff",
+	[EAPOL_KEY]		= "EAPOL-Key",
+	[EAPOL_ENCAP_ASF_ALERT]	= "EAPOL-Encap-ASF-Alert"
+};
+
+static inline const char *eap_get_type(int type)
+{
+	return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type];
+}
+
+struct eapol {
+	u8 snap[6];
+	u16 ethertype;
+	u8 version;
+	u8 type;
+	u16 length;
+} __attribute__ ((packed));
+
+#define IEEE80211_3ADDR_LEN 24
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_FCS_LEN    4
+
+#define MIN_FRAG_THRESHOLD     256U
+#define	MAX_FRAG_THRESHOLD     2346U
+
+/* Frame control field constants */
+#define IEEE80211_FCTL_VERS		0x0002
+#define IEEE80211_FCTL_FTYPE		0x000c
+#define IEEE80211_FCTL_STYPE		0x00f0
+#define IEEE80211_FCTL_TODS		0x0100
+#define IEEE80211_FCTL_FROMDS		0x0200
+#define IEEE80211_FCTL_MOREFRAGS	0x0400
+#define IEEE80211_FCTL_RETRY		0x0800
+#define IEEE80211_FCTL_PM		0x1000
+#define IEEE80211_FCTL_MOREDATA	0x2000
+#define IEEE80211_FCTL_WEP		0x4000
+#define IEEE80211_FCTL_ORDER		0x8000
+
+#define IEEE80211_FTYPE_MGMT		0x0000
+#define IEEE80211_FTYPE_CTL		0x0004
+#define IEEE80211_FTYPE_DATA		0x0008
+
+/* management */
+#define IEEE80211_STYPE_ASSOC_REQ	0x0000
+#define IEEE80211_STYPE_ASSOC_RESP 	0x0010
+#define IEEE80211_STYPE_REASSOC_REQ	0x0020
+#define IEEE80211_STYPE_REASSOC_RESP	0x0030
+#define IEEE80211_STYPE_PROBE_REQ	0x0040
+#define IEEE80211_STYPE_PROBE_RESP	0x0050
+#define IEEE80211_STYPE_BEACON		0x0080
+#define IEEE80211_STYPE_ATIM		0x0090
+#define IEEE80211_STYPE_DISASSOC	0x00A0
+#define IEEE80211_STYPE_AUTH		0x00B0
+#define IEEE80211_STYPE_DEAUTH		0x00C0
+
+/* control */
+#define IEEE80211_STYPE_PSPOLL		0x00A0
+#define IEEE80211_STYPE_RTS		0x00B0
+#define IEEE80211_STYPE_CTS		0x00C0
+#define IEEE80211_STYPE_ACK		0x00D0
+#define IEEE80211_STYPE_CFEND		0x00E0
+#define IEEE80211_STYPE_CFENDACK	0x00F0
+
+/* data */
+#define IEEE80211_STYPE_DATA		0x0000
+#define IEEE80211_STYPE_DATA_CFACK	0x0010
+#define IEEE80211_STYPE_DATA_CFPOLL	0x0020
+#define IEEE80211_STYPE_DATA_CFACKPOLL	0x0030
+#define IEEE80211_STYPE_NULLFUNC	0x0040
+#define IEEE80211_STYPE_CFACK		0x0050
+#define IEEE80211_STYPE_CFPOLL		0x0060
+#define IEEE80211_STYPE_CFACKPOLL	0x0070
+
+#define IEEE80211_SCTL_FRAG		0x000F
+#define IEEE80211_SCTL_SEQ		0xFFF0
+
+
+/* debug macros */
+
+#ifdef CONFIG_IEEE80211_DEBUG
+extern u32 ieee80211_debug_level;
+#define IEEE80211_DEBUG(level, fmt, args...) \
+do { if (ieee80211_debug_level & (level)) \
+  printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
+         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
+#endif	/* CONFIG_IEEE80211_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IEEE80211_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry.  xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your
+ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw/debug_level
+ *
+ * you simply need to add your entry to the ipw_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw then you do not have
+ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IEEE80211_DL_INFO          (1<<0)
+#define IEEE80211_DL_WX            (1<<1)
+#define IEEE80211_DL_SCAN          (1<<2)
+#define IEEE80211_DL_STATE         (1<<3)
+#define IEEE80211_DL_MGMT          (1<<4)
+#define IEEE80211_DL_FRAG          (1<<5)
+#define IEEE80211_DL_EAP           (1<<6)
+#define IEEE80211_DL_DROP          (1<<7)
+
+#define IEEE80211_DL_TX            (1<<8)
+#define IEEE80211_DL_RX            (1<<9)
+
+#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
+#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
+#define IEEE80211_DEBUG_INFO(f, a...)   IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a)
+
+#define IEEE80211_DEBUG_WX(f, a...)     IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a)
+#define IEEE80211_DEBUG_SCAN(f, a...)   IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a)
+#define IEEE80211_DEBUG_STATE(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
+#define IEEE80211_DEBUG_MGMT(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
+#define IEEE80211_DEBUG_FRAG(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
+#define IEEE80211_DEBUG_EAP(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
+#define IEEE80211_DEBUG_DROP(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
+#define IEEE80211_DEBUG_TX(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
+#define IEEE80211_DEBUG_RX(f, a...)  IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h> /* ARPHRD_ETHER */
+
+#ifndef WIRELESS_SPY
+#define WIRELESS_SPY		// enable iwspy support
+#endif
+#include <net/iw_handler.h>	// new driver API
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
+#endif
+
+/* IEEE 802.11 defines */
+
+#define P80211_OUI_LEN 3
+
+struct ieee80211_snap_hdr {
+
+        u8    dsap;   /* always 0xAA */
+        u8    ssap;   /* always 0xAA */
+        u8    ctrl;   /* always 0x03 */
+        u8    oui[P80211_OUI_LEN];    /* organizational universal id */
+
+} __attribute__ ((packed));
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
+#define WLAN_GET_SEQ_SEQ(seq)  ((seq) & IEEE80211_SCTL_SEQ)
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_IBSS (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
+#define WLAN_CAPABILITY_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_CHALLENGE 16
+#define WLAN_EID_RSN 48
+#define WLAN_EID_GENERIC 221
+
+#define IEEE80211_MGMT_HDR_LEN 24
+#define IEEE80211_DATA_HDR3_LEN 24
+#define IEEE80211_DATA_HDR4_LEN 30
+
+
+#define IEEE80211_STATMASK_SIGNAL (1<<0)
+#define IEEE80211_STATMASK_RSSI (1<<1)
+#define IEEE80211_STATMASK_NOISE (1<<2)
+#define IEEE80211_STATMASK_RATE (1<<3)
+#define IEEE80211_STATMASK_WEMASK 0x7
+
+
+#define IEEE80211_CCK_MODULATION    (1<<0)
+#define IEEE80211_OFDM_MODULATION   (1<<1)
+
+#define IEEE80211_24GHZ_BAND     (1<<0)
+#define IEEE80211_52GHZ_BAND     (1<<1)
+
+#define IEEE80211_CCK_RATE_1MB		        0x02
+#define IEEE80211_CCK_RATE_2MB		        0x04
+#define IEEE80211_CCK_RATE_5MB		        0x0B
+#define IEEE80211_CCK_RATE_11MB		        0x16
+#define IEEE80211_OFDM_RATE_6MB		        0x0C
+#define IEEE80211_OFDM_RATE_9MB		        0x12
+#define IEEE80211_OFDM_RATE_12MB		0x18
+#define IEEE80211_OFDM_RATE_18MB		0x24
+#define IEEE80211_OFDM_RATE_24MB		0x30
+#define IEEE80211_OFDM_RATE_36MB		0x48
+#define IEEE80211_OFDM_RATE_48MB		0x60
+#define IEEE80211_OFDM_RATE_54MB		0x6C
+#define IEEE80211_BASIC_RATE_MASK		0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK		(1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK		(1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK		(1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK		(1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK		(1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK		(1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK		(1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK		(1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK		(1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK		(1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK		(1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK		(1<<11)
+
+#define IEEE80211_CCK_RATES_MASK	        0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK	(IEEE80211_CCK_RATE_1MB_MASK | \
+	IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK	(IEEE80211_CCK_BASIC_RATES_MASK | \
+        IEEE80211_CCK_RATE_5MB_MASK | \
+        IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK		0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK	(IEEE80211_OFDM_RATE_6MB_MASK | \
+	IEEE80211_OFDM_RATE_12MB_MASK | \
+	IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK	(IEEE80211_OFDM_BASIC_RATES_MASK | \
+	IEEE80211_OFDM_RATE_9MB_MASK  | \
+	IEEE80211_OFDM_RATE_18MB_MASK | \
+	IEEE80211_OFDM_RATE_36MB_MASK | \
+	IEEE80211_OFDM_RATE_48MB_MASK | \
+	IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
+                                IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+#define IEEE80211_NUM_OFDM_RATES	    8
+#define IEEE80211_NUM_CCK_RATES	            4
+#define IEEE80211_OFDM_SHIFT_MASK_A         4
+
+
+
+
+/* NOTE: This data is for statistical purposes; not all hardware provides this
+ *       information for frames received.  Not setting these will not cause
+ *       any adverse affects. */
+struct ieee80211_rx_stats {
+	u32 mac_time;
+	s8 rssi;
+	u8 signal;
+	u8 noise;
+	u16 rate; /* in 100 kbps */
+	u8 received_channel;
+	u8 control;
+	u8 mask;
+	u8 freq;
+	u16 len;
+};
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define IEEE80211_FRAG_CACHE_LEN 4
+
+struct ieee80211_frag_entry {
+	unsigned long first_frag_time;
+	unsigned int seq;
+	unsigned int last_frag;
+	struct sk_buff *skb;
+	u8 src_addr[ETH_ALEN];
+	u8 dst_addr[ETH_ALEN];
+};
+
+struct ieee80211_stats {
+	unsigned int tx_unicast_frames;
+	unsigned int tx_multicast_frames;
+	unsigned int tx_fragments;
+	unsigned int tx_unicast_octets;
+	unsigned int tx_multicast_octets;
+	unsigned int tx_deferred_transmissions;
+	unsigned int tx_single_retry_frames;
+	unsigned int tx_multiple_retry_frames;
+	unsigned int tx_retry_limit_exceeded;
+	unsigned int tx_discards;
+	unsigned int rx_unicast_frames;
+	unsigned int rx_multicast_frames;
+	unsigned int rx_fragments;
+	unsigned int rx_unicast_octets;
+	unsigned int rx_multicast_octets;
+	unsigned int rx_fcs_errors;
+	unsigned int rx_discards_no_buffer;
+	unsigned int tx_discards_wrong_sa;
+	unsigned int rx_discards_undecryptable;
+	unsigned int rx_message_in_msg_fragments;
+	unsigned int rx_message_in_bad_msg_fragments;
+};
+
+struct ieee80211_device;
+
+#define SEC_KEY_1         (1<<0)
+#define SEC_KEY_2         (1<<1)
+#define SEC_KEY_3         (1<<2)
+#define SEC_KEY_4         (1<<3)
+#define SEC_ACTIVE_KEY    (1<<4)
+#define SEC_AUTH_MODE     (1<<5)
+#define SEC_UNICAST_GROUP (1<<6)
+#define SEC_LEVEL         (1<<7)
+#define SEC_ENABLED       (1<<8)
+
+#define SEC_LEVEL_0      0 /* None */
+#define SEC_LEVEL_1      1 /* WEP 40 and 104 bit */
+#define SEC_LEVEL_2      2 /* Level 1 + TKIP */
+#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
+#define SEC_LEVEL_3      4 /* Level 2 + CCMP */
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+
+struct ieee80211_security {
+	u16 active_key:2,
+            enabled:1,
+	    auth_mode:2,
+            auth_algo:4,
+            unicast_uses_group:1;
+	u8 key_sizes[WEP_KEYS];
+	u8 keys[WEP_KEYS][WEP_KEY_LEN];
+	u8 level;
+	u16 flags;
+} __attribute__ ((packed));
+
+
+/*
+
+ 802.11 data frame from AP
+
+      ,-------------------------------------------------------------------.
+Bytes |  2   |  2   |    6    |    6    |    6    |  2   | 0..2312 |   4  |
+      |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura |  DA/RA  |   TA    |    SA   | Sequ |  frame  |  fcs |
+      |      | tion | (BSSID) |         |         | ence |  data   |      |
+      `-------------------------------------------------------------------'
+
+Total: 28-2340 bytes
+
+*/
+
+struct ieee80211_header_data {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[6];
+	u8 addr2[6];
+	u8 addr3[6];
+	u16 seq_ctrl;
+};
+
+#define BEACON_PROBE_SSID_ID_POSITION 12
+
+/* Management Frame Information Element Types */
+#define MFIE_TYPE_SSID       0
+#define MFIE_TYPE_RATES      1
+#define MFIE_TYPE_FH_SET     2
+#define MFIE_TYPE_DS_SET     3
+#define MFIE_TYPE_CF_SET     4
+#define MFIE_TYPE_TIM        5
+#define MFIE_TYPE_IBSS_SET   6
+#define MFIE_TYPE_CHALLENGE  16
+#define MFIE_TYPE_RSN	     48
+#define MFIE_TYPE_RATES_EX   50
+#define MFIE_TYPE_GENERIC    221
+
+struct ieee80211_info_element_hdr {
+	u8 id;
+	u8 len;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+	u8 id;
+	u8 len;
+	u8 data[0];
+} __attribute__ ((packed));
+
+/*
+ * These are the data types that can make up management packets
+ *
+	u16 auth_algorithm;
+	u16 auth_sequence;
+	u16 beacon_interval;
+	u16 capability;
+	u8 current_ap[ETH_ALEN];
+	u16 listen_interval;
+	struct {
+		u16 association_id:14, reserved:2;
+	} __attribute__ ((packed));
+	u32 time_stamp[2];
+	u16 reason;
+	u16 status;
+*/
+
+struct ieee80211_authentication {
+	struct ieee80211_header_data header;
+	u16 algorithm;
+	u16 transaction;
+	u16 status;
+	struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+
+struct ieee80211_probe_response {
+	struct ieee80211_header_data header;
+	u32 time_stamp[2];
+	u16 beacon_interval;
+	u16 capability;
+	struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_request_frame {
+	u16 capability;
+	u16 listen_interval;
+	u8 current_ap[ETH_ALEN];
+	struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_response_frame {
+	struct ieee80211_hdr_3addr header;
+	u16 capability;
+	u16 status;
+	u16 aid;
+	struct ieee80211_info_element info_element; /* supported rates */
+} __attribute__ ((packed));
+
+
+struct ieee80211_txb {
+	u8 nr_frags;
+	u8 encrypted;
+	u16 reserved;
+	u16 frag_size;
+	u16 payload_size;
+	struct sk_buff *fragments[0];
+};
+
+
+/* SWEEP TABLE ENTRIES NUMBER*/
+#define MAX_SWEEP_TAB_ENTRIES		  42
+#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET  7
+/* MAX_RATES_LENGTH needs to be 12.  The spec says 8, and many APs
+ * only use 8, and then use extended rates for the remaining supported
+ * rates.  Other APs, however, stick all of their supported rates on the
+ * main rates information element... */
+#define MAX_RATES_LENGTH                  ((u8)12)
+#define MAX_RATES_EX_LENGTH               ((u8)16)
+#define MAX_NETWORK_COUNT                  128
+
+#define CRC_LENGTH                 4U
+
+#define MAX_WPA_IE_LEN 64
+
+#define NETWORK_EMPTY_ESSID (1<<0)
+#define NETWORK_HAS_OFDM    (1<<1)
+#define NETWORK_HAS_CCK     (1<<2)
+
+struct ieee80211_network {
+	/* These entries are used to identify a unique network */
+	u8 bssid[ETH_ALEN];
+	u8 channel;
+	/* Ensure null-terminated for any debug msgs */
+	u8 ssid[IW_ESSID_MAX_SIZE + 1];
+	u8 ssid_len;
+
+	/* These are network statistics */
+	struct ieee80211_rx_stats stats;
+	u16 capability;
+	u8 rates[MAX_RATES_LENGTH];
+	u8 rates_len;
+	u8 rates_ex[MAX_RATES_EX_LENGTH];
+	u8 rates_ex_len;
+	unsigned long last_scanned;
+	u8 mode;
+	u8 flags;
+	u32 last_associate;
+	u32 time_stamp[2];
+	u16 beacon_interval;
+	u16 listen_interval;
+	u16 atim_window;
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	size_t wpa_ie_len;
+	u8 rsn_ie[MAX_WPA_IE_LEN];
+	size_t rsn_ie_len;
+	struct list_head list;
+};
+
+enum ieee80211_state {
+	IEEE80211_UNINITIALIZED = 0,
+	IEEE80211_INITIALIZED,
+	IEEE80211_ASSOCIATING,
+	IEEE80211_ASSOCIATED,
+	IEEE80211_AUTHENTICATING,
+	IEEE80211_AUTHENTICATED,
+	IEEE80211_SHUTDOWN
+};
+
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+#define DEFAULT_FTS 2346
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
+
+
+extern inline int is_broadcast_ether_addr(const u8 *addr)
+{
+	return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) &&   \
+		(addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff));
+}
+
+#define CFG_IEEE80211_RESERVE_FCS (1<<0)
+#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
+
+struct ieee80211_device {
+	struct net_device *dev;
+
+	/* Bookkeeping structures */
+	struct net_device_stats stats;
+	struct ieee80211_stats ieee_stats;
+
+	/* Probe / Beacon management */
+	struct list_head network_free_list;
+	struct list_head network_list;
+	struct ieee80211_network *networks;
+	int scans;
+	int scan_age;
+
+	int iw_mode; /* operating mode (IW_MODE_*) */
+
+	spinlock_t lock;
+
+	int tx_headroom; /* Set to size of any additional room needed at front
+			  * of allocated Tx SKBs */
+	u32 config;
+
+	/* WEP and other encryption related settings at the device level */
+	int open_wep; /* Set to 1 to allow unencrypted frames */
+
+	int reset_on_keychange; /* Set to 1 if the HW needs to be reset on
+				 * WEP key changes */
+
+	/* If the host performs {en,de}cryption, then set to 1 */
+	int host_encrypt;
+	int host_decrypt;
+	int ieee802_1x; /* is IEEE 802.1X used */
+
+	/* WPA data */
+	int wpa_enabled;
+	int drop_unencrypted;
+	int tkip_countermeasures;
+	int privacy_invoked;
+	size_t wpa_ie_len;
+	u8 *wpa_ie;
+
+	struct list_head crypt_deinit_list;
+	struct ieee80211_crypt_data *crypt[WEP_KEYS];
+	int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
+	struct timer_list crypt_deinit_timer;
+
+	int bcrx_sta_key; /* use individual keys to override default keys even
+			   * with RX of broad/multicast frames */
+
+	/* Fragmentation structures */
+	struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN];
+	unsigned int frag_next_idx;
+	u16 fts; /* Fragmentation Threshold */
+
+	/* Association info */
+	u8 bssid[ETH_ALEN];
+
+	enum ieee80211_state state;
+
+	int mode;       /* A, B, G */
+	int modulation; /* CCK, OFDM */
+	int freq_band;  /* 2.4Ghz, 5.2Ghz, Mixed */
+	int abg_ture;   /* ABG flag              */
+
+	/* Callback functions */
+	void (*set_security)(struct net_device *dev,
+			     struct ieee80211_security *sec);
+	int (*hard_start_xmit)(struct ieee80211_txb *txb,
+			       struct net_device *dev);
+	int (*reset_port)(struct net_device *dev);
+
+	/* This must be the last item so that it points to the data
+	 * allocated beyond this structure by alloc_ieee80211 */
+	u8 priv[0];
+};
+
+#define IEEE_A            (1<<0)
+#define IEEE_B            (1<<1)
+#define IEEE_G            (1<<2)
+#define IEEE_MODE_MASK    (IEEE_A|IEEE_B|IEEE_G)
+
+extern inline void *ieee80211_priv(struct net_device *dev)
+{
+	return ((struct ieee80211_device *)netdev_priv(dev))->priv;
+}
+
+extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
+{
+	/* Single white space is for Linksys APs */
+	if (essid_len == 1 && essid[0] == ' ')
+		return 1;
+
+	/* Otherwise, if the entire essid is 0, we assume it is hidden */
+	while (essid_len) {
+		essid_len--;
+		if (essid[essid_len] != '\0')
+			return 0;
+	}
+
+	return 1;
+}
+
+extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode)
+{
+	/*
+	 * It is possible for both access points and our device to support
+	 * combinations of modes, so as long as there is one valid combination
+	 * of ap/device supported modes, then return success
+	 *
+	 */
+	if ((mode & IEEE_A) &&
+	    (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+	    (ieee->freq_band & IEEE80211_52GHZ_BAND))
+		return 1;
+
+	if ((mode & IEEE_G) &&
+	    (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+	    (ieee->freq_band & IEEE80211_24GHZ_BAND))
+		return 1;
+
+	if ((mode & IEEE_B) &&
+	    (ieee->modulation & IEEE80211_CCK_MODULATION) &&
+	    (ieee->freq_band & IEEE80211_24GHZ_BAND))
+		return 1;
+
+	return 0;
+}
+
+extern inline int ieee80211_get_hdrlen(u16 fc)
+{
+	int hdrlen = 24;
+
+	switch (WLAN_FC_GET_TYPE(fc)) {
+	case IEEE80211_FTYPE_DATA:
+		if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+			hdrlen = 30; /* Addr4 */
+		break;
+	case IEEE80211_FTYPE_CTL:
+		switch (WLAN_FC_GET_STYPE(fc)) {
+		case IEEE80211_STYPE_CTS:
+		case IEEE80211_STYPE_ACK:
+			hdrlen = 10;
+			break;
+		default:
+			hdrlen = 16;
+			break;
+		}
+		break;
+	}
+
+	return hdrlen;
+}
+
+
+
+/* ieee80211.c */
+extern void free_ieee80211(struct net_device *dev);
+extern struct net_device *alloc_ieee80211(int sizeof_priv);
+
+extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
+
+/* ieee80211_tx.c */
+
+
+extern int ieee80211_xmit(struct sk_buff *skb,
+			  struct net_device *dev);
+extern void ieee80211_txb_free(struct ieee80211_txb *);
+
+
+/* ieee80211_rx.c */
+extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+			struct ieee80211_rx_stats *rx_stats);
+extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+			     struct ieee80211_hdr *header,
+			     struct ieee80211_rx_stats *stats);
+
+/* iee80211_wx.c */
+extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+				   struct iw_request_info *info,
+				   union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+				   struct iw_request_info *info,
+				   union iwreq_data *wrqu, char *key);
+
+
+extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
+{
+	ieee->scans++;
+}
+
+extern inline int ieee80211_get_scans(struct ieee80211_device *ieee)
+{
+	return ieee->scans;
+}
+
+static inline const char *escape_essid(const char *essid, u8 essid_len) {
+	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+	const char *s = essid;
+	char *d = escaped;
+
+	if (ieee80211_is_empty_essid(essid, essid_len)) {
+		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+		return escaped;
+	}
+
+	essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
+	while (essid_len--) {
+		if (*s == '\0') {
+			*d++ = '\\';
+			*d++ = '0';
+			s++;
+		} else {
+			*d++ = *s++;
+		}
+	}
+	*d = '\0';
+	return escaped;
+}
+
+#endif /* IEEE80211_H */
diff --git a/kernel/exit.c b/kernel/exit.c
index 3ebcd60..9d1b10e 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -784,6 +784,8 @@
 
 	profile_task_exit(tsk);
 
+	WARN_ON(atomic_read(&tsk->fs_excl));
+
 	if (unlikely(in_interrupt()))
 		panic("Aiee, killing interrupt handler!");
 	if (unlikely(!tsk->pid))
diff --git a/kernel/fork.c b/kernel/fork.c
index 2c78068..cdef6ce 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1090,6 +1090,11 @@
 		spin_unlock(&current->sighand->siglock);
 	}
 
+	/*
+	 * inherit ioprio
+	 */
+	p->ioprio = current->ioprio;
+
 	SET_LINKS(p);
 	if (unlikely(p->ptrace & PT_PTRACED))
 		__ptrace_link(p, current->parent);
diff --git a/kernel/sched.c b/kernel/sched.c
index a07cff9..e2b0d3e 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3448,15 +3448,7 @@
 {
 	return TASK_NICE(p);
 }
-
-/*
- * The only users of task_nice are binfmt_elf and binfmt_elf32.
- * binfmt_elf is no longer modular, but binfmt_elf32 still is.
- * Therefore, task_nice is needed if there is a compat_mode.
- */
-#ifdef CONFIG_COMPAT
 EXPORT_SYMBOL_GPL(task_nice);
-#endif
 
 /**
  * idle_cpu - is a given cpu idle currently?
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7ee675a..3c9f7f8 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1667,9 +1667,8 @@
 #ifdef WANT_PAGE_VIRTUAL
 		/* The shift won't overflow because ZONE_NORMAL is below 4G. */
 		if (!is_highmem_idx(zone))
-			set_page_address(page, __va(start_pfn << PAGE_SHIFT));
+			set_page_address(page, __va(pfn << PAGE_SHIFT));
 #endif
-		start_pfn++;
 	}
 }
 
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 3b1fafc..7bd95ce 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -52,7 +52,7 @@
 
 config SOUND_CMPCI_JOYSTICK
 	bool "Enable joystick"
-	depends on SOUND_CMPCI && X86
+	depends on SOUND_CMPCI && X86 && (GAMEPORT=y || SOUND_CMPCI=GAMEPORT)
 	help
 	  Say Y here in order to enable the joystick port on a sound card using
 	  the CMI8338 or the CMI8738 chipset.  You need to config the
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 3310866..2704e15 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -255,7 +255,7 @@
 
 static volatile struct dbdma_cmd *emergency_dbdma_cmd;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * Stuff for restoring after a sleep.
  */
@@ -263,7 +263,7 @@
 struct pmu_sleep_notifier awacs_sleep_notifier = {
 	awacs_sleep_notify, SLEEP_LEVEL_SOUND,
 };
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 /* for (soft) sample rate translations */
 int expand_bal;		/* Balance factor for expanding (not volume!) */
@@ -675,7 +675,7 @@
 	kfree(awacs_rx_cmd_space);
 	kfree(beep_dbdma_cmd_space);
 	kfree(beep_buf);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
 #endif
 }
@@ -1415,7 +1415,7 @@
 	}
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /*
  * Save state when going to sleep, restore it afterwards.
  */
@@ -1551,7 +1551,7 @@
 	}
 	return PBOOK_SLEEP_OK;
 }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 
 /* All the burgundy functions: */
@@ -3053,9 +3053,9 @@
 	if ((res=setup_beep()))
 		return res ;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	pmu_register_sleep_notifier(&awacs_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 	/* Powerbooks have odd ways of enabling inputs such as
 	   an expansion-bay CD or sound from an internal modem
diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c
index 886f61c..8538085 100644
--- a/sound/oss/es1370.c
+++ b/sound/oss/es1370.c
@@ -162,6 +162,10 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -385,7 +389,10 @@
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
+#ifdef SUPPORT_JOYSTICK
 	struct gameport *gameport;
+#endif
+
 	struct semaphore sem;
 };
 
@@ -2554,10 +2561,55 @@
 	{ SOUND_MIXER_WRITE_OGAIN, 0x4040 }
 };
 
+#ifdef SUPPORT_JOYSTICK
+
+static int __devinit es1370_register_gameport(struct es1370_state *s)
+{
+	struct gameport *gp;
+
+	if (!request_region(0x200, JOY_EXTENT, "es1370")) {
+		printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
+		return -EBUSY;
+	}
+
+	s->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
+		release_region(0x200, JOY_EXTENT);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ESS1370");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
+	gp->dev.parent = &s->dev->dev;
+	gp->io = 0x200;
+
+	s->ctrl |= CTRL_JYSTK_EN;
+	outl(s->ctrl, s->io + ES1370_REG_CONTROL);
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
+static inline void es1370_unregister_gameport(struct es1370_state *s)
+{
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, JOY_EXTENT);
+
+	}
+}
+
+#else
+static inline int es1370_register_gameport(struct es1370_state *s) { return -ENOSYS; }
+static inline void es1370_unregister_gameport(struct es1370_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct es1370_state *s;
-	struct gameport *gp = NULL;
 	mm_segment_t fs;
 	int i, val, ret;
 
@@ -2606,28 +2658,14 @@
 	/* note: setting CTRL_SERR_DIS is reported to break
 	 * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
 	s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
-	if (!request_region(0x200, JOY_EXTENT, "es1370")) {
-		printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
-	} else if (!(s->gameport = gp = gameport_allocate_port())) {
-		printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
-		release_region(0x200, JOY_EXTENT);
-	} else {
-		gameport_set_name(gp, "ESS1370");
-		gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
-		gp->dev.parent = &s->dev->dev;
-		gp->io = 0x200;
-		s->ctrl |= CTRL_JYSTK_EN;
-	}
 	if (lineout[devindex])
 		s->ctrl |= CTRL_XCTL0;
 	if (micbias[devindex])
 		s->ctrl |= CTRL_XCTL1;
 	s->sctrl = 0;
-	printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n"
-	       KERN_INFO "es1370: features: joystick %s, line %s, mic impedance %s\n",
-	       s->io, s->irq, (s->ctrl & CTRL_JYSTK_EN) ? "on" : "off",
-	       (s->ctrl & CTRL_XCTL0) ? "out" : "in",
-		       (s->ctrl & CTRL_XCTL1) ? "1" : "0");
+	printk(KERN_INFO "es1370: adapter at io %#lx irq %u, line %s, mic impedance %s\n",
+	       s->io, s->irq, (s->ctrl & CTRL_XCTL0) ? "out" : "in",
+	       (s->ctrl & CTRL_XCTL1) ? "1" : "0");
 	/* register devices */
 	if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) {
 		ret = s->dev_audio;
@@ -2673,9 +2711,7 @@
 	}
 	set_fs(fs);
 
-	/* register gameport */
-	if (gp)
-		gameport_register_port(gp);
+	es1370_register_gameport(s);
 
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
@@ -2697,10 +2733,6 @@
  err_dev1:
 	printk(KERN_ERR "es1370: cannot register misc device\n");
 	free_irq(s->irq, s);
-	if (s->gameport) {
-		release_region(s->gameport->io, JOY_EXTENT);
-		gameport_free_port(s->gameport);
-	}
  err_irq:
 	release_region(s->io, ES1370_EXTENT);
  err_region:
@@ -2719,11 +2751,7 @@
 	outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
 	synchronize_irq(s->irq);
 	free_irq(s->irq, s);
-	if (s->gameport) {
-		int gpio = s->gameport->io;
-		gameport_unregister_port(s->gameport);
-		release_region(gpio, JOY_EXTENT);
-	}
+	es1370_unregister_gameport(s);
 	release_region(s->io, ES1370_EXTENT);
 	unregister_sound_dsp(s->dev_audio);
 	unregister_sound_mixer(s->dev_mixer);
diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
index 9266b77..12a56d5 100644
--- a/sound/oss/es1371.c
+++ b/sound/oss/es1371.c
@@ -134,6 +134,10 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -454,7 +458,10 @@
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
+#ifdef SUPPORT_JOYSTICK
 	struct gameport *gameport;
+#endif
+
 	struct semaphore sem;
 };
 
@@ -2787,12 +2794,63 @@
 	{ PCI_ANY_ID, PCI_ANY_ID }
 };
 
+#ifdef SUPPORT_JOYSTICK
+
+static int __devinit es1371_register_gameport(struct es1371_state *s)
+{
+	struct gameport *gp;
+	int gpio;
+
+	for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
+		if (request_region(gpio, JOY_EXTENT, "es1371"))
+			break;
+
+	if (gpio < 0x200) {
+		printk(KERN_ERR PFX "no free joystick address found\n");
+		return -EBUSY;
+	}
+
+	s->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR PFX "can not allocate memory for gameport\n");
+		release_region(gpio, JOY_EXTENT);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ESS1371 Gameport");
+	gameport_set_phys(gp, "isa%04x/gameport0", gpio);
+	gp->dev.parent = &s->dev->dev;
+	gp->io = gpio;
+
+	s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+	outl(s->ctrl, s->io + ES1371_REG_CONTROL);
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
+static inline void es1371_unregister_gameport(struct es1371_state *s)
+{
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, JOY_EXTENT);
+
+	}
+}
+
+#else
+static inline int es1371_register_gameport(struct es1371_state *s) { return -ENOSYS; }
+static inline void es1371_unregister_gameport(struct es1371_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
+
 static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct es1371_state *s;
-	struct gameport *gp;
 	mm_segment_t fs;
-	int i, gpio, val, res = -1;
+	int i, val, res = -1;
 	int idx;
 	unsigned long tmo;
 	signed long tmo2;
@@ -2883,23 +2941,6 @@
 		}
 	}
 
-	for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
-		if (request_region(gpio, JOY_EXTENT, "es1371"))
-			break;
-
-	if (gpio < 0x200) {
-		printk(KERN_ERR PFX "no free joystick address found\n");
-	} else if (!(s->gameport = gp = gameport_allocate_port())) {
-		printk(KERN_ERR PFX "can not allocate memory for gameport\n");
-		release_region(gpio, JOY_EXTENT);
-	} else {
-		gameport_set_name(gp, "ESS1371 Gameport");
-		gameport_set_phys(gp, "isa%04x/gameport0", gpio);
-		gp->dev.parent = &s->dev->dev;
-		gp->io = gpio;
-		s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
-	}
-
 	s->sctrl = 0;
 	cssr = 0;
 	s->spdif_volume = -1;
@@ -2969,9 +3010,7 @@
 	/* turn on S/PDIF output driver if requested */
 	outl(cssr, s->io+ES1371_REG_STATUS);
 
-	/* register gameport */
-	if (s->gameport)
-		gameport_register_port(s->gameport);
+	es1371_register_gameport(s);
 
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
@@ -2980,13 +3019,9 @@
 	/* increment devindex */
 	if (devindex < NR_DEVICE-1)
 		devindex++;
-       	return 0;
+	return 0;
 
  err_gp:
-	if (s->gameport) {
-		release_region(s->gameport->io, JOY_EXTENT);
-		gameport_free_port(s->gameport);
-	}
 #ifdef ES1371_DEBUG
 	if (s->ps)
 		remove_proc_entry("es1371", NULL);
@@ -3025,11 +3060,7 @@
 	outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
 	synchronize_irq(s->irq);
 	free_irq(s->irq, s);
-	if (s->gameport) {
-		int gpio = s->gameport->io;
-		gameport_unregister_port(s->gameport);
-		release_region(gpio, JOY_EXTENT);
-	}
+	es1371_unregister_gameport(s);
 	release_region(s->io, ES1371_EXTENT);
 	unregister_sound_dsp(s->dev_audio);
 	unregister_sound_mixer(s->codec->dev_mixer);
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
index fb09065..a4ecab2f 100644
--- a/sound/oss/esssolo1.c
+++ b/sound/oss/esssolo1.c
@@ -150,6 +150,10 @@
 
 #define FMODE_DMFM 0x10
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 static struct pci_driver solo1_driver;
 
 /* --------------------------------------------------------------------- */
@@ -227,7 +231,9 @@
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
+#if SUPPORT_JOYSTICK
 	struct gameport *gameport;
+#endif
 };
 
 /* --------------------------------------------------------------------- */
@@ -2281,6 +2287,7 @@
 	return 0;
 }
 
+#ifdef SUPPORT_JOYSTICK
 static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
 {
 	struct gameport *gp;
@@ -2307,6 +2314,19 @@
 	return 0;
 }
 
+static inline void solo1_unregister_gameport(struct solo1_state *s)
+{
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, GAMEPORT_EXTENT);
+	}
+}
+#else
+static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; }
+static inline void solo1_unregister_gameport(struct solo1_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct solo1_state *s;
@@ -2438,11 +2458,7 @@
 	synchronize_irq(s->irq);
 	pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
 	free_irq(s->irq, s);
-	if (s->gameport) {
-		int gpio = s->gameport->io;
-		gameport_unregister_port(s->gameport);
-		release_region(gpio, GAMEPORT_EXTENT);
-	}
+	solo1_unregister_gameport(s);
 	release_region(s->iobase, IOBASE_EXTENT);
 	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
 	release_region(s->ddmabase, DDMABASE_EXTENT);
diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c
index a7067f1..aa3c50d 100644
--- a/sound/oss/mad16.c
+++ b/sound/oss/mad16.c
@@ -50,9 +50,12 @@
 #include "sb.h"
 #include "mpu401.h"
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 static int      mad16_conf;
 static int      mad16_cdsel;
-static struct gameport *gameport;
 static DEFINE_SPINLOCK(lock);
 
 #define C928	1
@@ -902,6 +905,10 @@
 	-1, -1, -1, -1
 };
 
+#ifdef SUPPORT_JOYSTICK
+
+static struct gameport *gameport;
+
 static int __devinit mad16_register_gameport(int io_port)
 {
 	if (!request_region(io_port, 1, "mad16 gameport")) {
@@ -925,6 +932,20 @@
 	return 0;
 }
 
+static inline void mad16_unregister_gameport(void)
+{
+	if (gameport) {
+		/* the gameport was initialized so we must free it up */
+		gameport_unregister_port(gameport);
+		gameport = NULL;
+		release_region(0x201, 1);
+	}
+}
+#else
+static inline int mad16_register_gameport(int io_port) { return -ENOSYS; }
+static inline void mad16_unregister_gameport(void) { }
+#endif
+
 static int __devinit init_mad16(void)
 {
 	int dmatype = 0;
@@ -1060,12 +1081,7 @@
 {
 	if (found_mpu)
 		unload_mad16_mpu(&cfg_mpu);
-	if (gameport) {
-		/* the gameport was initialized so we must free it up */
-		gameport_unregister_port(gameport);
-		gameport = NULL;
-		release_region(0x201, 1);
-	}
+	mad16_unregister_gameport();
 	unload_mad16(&cfg);
 	release_region(MC0_PORT, 12);
 }
diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
index 06047e7..17d0e46 100644
--- a/sound/oss/sonicvibes.c
+++ b/sound/oss/sonicvibes.c
@@ -122,6 +122,9 @@
 
 #include "dm.h"
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
 
 /* --------------------------------------------------------------------- */
 
@@ -365,7 +368,9 @@
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
+#if SUPPORT_JOYSTICK
 	struct gameport *gameport;
+#endif
 };
 
 /* --------------------------------------------------------------------- */
@@ -2485,6 +2490,7 @@
 #define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
 				 (pci_resource_flags((dev), (num)) & IORESOURCE_IO))
 
+#ifdef SUPPORT_JOYSTICK
 static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
 {
 	struct gameport *gp;
@@ -2511,6 +2517,19 @@
 	return 0;
 }
 
+static inline void sv_unregister_gameport(struct sv_state *s)
+{
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, SV_EXTENT_GAME);
+	}
+}
+#else
+static inline int sv_register_gameport(struct sv_state *s, int io_port) { return -ENOSYS; }
+static inline void sv_unregister_gameport(struct sv_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
@@ -2711,11 +2730,7 @@
 	/*outb(0, s->iodmaa + SV_DMA_RESET);*/
 	/*outb(0, s->iodmac + SV_DMA_RESET);*/
 	free_irq(s->irq, s);
-	if (s->gameport) {
-		int gpio = s->gameport->io;
-		gameport_unregister_port(s->gameport);
-		release_region(gpio, SV_EXTENT_GAME);
-	}
+	sv_unregister_gameport(s);
 	release_region(s->iodmac, SV_EXTENT_DMA);
 	release_region(s->iodmaa, SV_EXTENT_DMA);
 	release_region(s->ioenh, SV_EXTENT_ENH);
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index 47537f0..5f0ad6b 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -228,6 +228,10 @@
 
 #define DRIVER_VERSION "0.14.10j-2.6"
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 /* magic numbers to protect our data structures */
 #define TRIDENT_CARD_MAGIC	0x5072696E	/* "Prin" */
 #define TRIDENT_STATE_MAGIC	0x63657373	/* "cess" */
@@ -4252,24 +4256,25 @@
 	return num_ac97 + 1;
 }
 
+#ifdef SUPPORT_JOYSTICK
 /* Gameport functions for the cards ADC gameport */
 
-static unsigned char
-trident_game_read(struct gameport *gameport)
+static unsigned char trident_game_read(struct gameport *gameport)
 {
 	struct trident_card *card = gameport->port_data;
+
 	return inb(TRID_REG(card, T4D_GAME_LEG));
 }
 
-static void
-trident_game_trigger(struct gameport *gameport)
+static void trident_game_trigger(struct gameport *gameport)
 {
 	struct trident_card *card = gameport->port_data;
+
 	outb(0xff, TRID_REG(card, T4D_GAME_LEG));
 }
 
-static int
-trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+static int trident_game_cooked_read(struct gameport *gameport,
+				    int *axes, int *buttons)
 {
 	struct trident_card *card = gameport->port_data;
 	int i;
@@ -4285,8 +4290,7 @@
 	return 0;
 }
 
-static int
-trident_game_open(struct gameport *gameport, int mode)
+static int trident_game_open(struct gameport *gameport, int mode)
 {
 	struct trident_card *card = gameport->port_data;
 
@@ -4305,8 +4309,7 @@
 	return 0;
 }
 
-static int __devinit
-trident_register_gameport(struct trident_card *card)
+static int __devinit trident_register_gameport(struct trident_card *card)
 {
 	struct gameport *gp;
 
@@ -4330,6 +4333,17 @@
 	return 0;
 }
 
+static inline void trident_unregister_gameport(struct trident_card *card)
+{
+	if (card->gameport)
+		gameport_unregister_port(card->gameport);
+}
+
+#else
+static inline int trident_register_gameport(struct trident_card *card) { return -ENOSYS; }
+static inline void trident_unregister_gameport(struct trident_card *card) { }
+#endif /* SUPPORT_JOYSTICK */
+
 /* install the driver, we do not allocate hardware channel nor DMA buffer */ 
 /* now, they are defered until "ACCESS" time (in prog_dmabuf called by */ 
 /* open/read/write/ioctl/mmap) */
@@ -4569,8 +4583,7 @@
 	}
 
 	/* Unregister gameport */
-	if (card->gameport)
-		gameport_unregister_port(card->gameport);
+	trident_unregister_gameport(card);
 
 	/* Kill interrupts, and SP/DIF */
 	trident_disable_loop_interrupts(card);
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
index b387e1e5..83edda9 100644
--- a/sound/oss/via82cxxx_audio.c
+++ b/sound/oss/via82cxxx_audio.c
@@ -35,6 +35,7 @@
 #include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
@@ -3391,10 +3392,10 @@
 	if (rc)
 		goto err_out_disable;
 
-	rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+	rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 	if (rc)
 		goto err_out_res;
-	rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+	rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 	if (rc)
 		goto err_out_res;
 
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index b6e1854..eb3c52b 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1338,11 +1338,6 @@
 static inline void snd_cs4281_free_gameport(cs4281_t *chip) { }
 #endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */
 
-
-/*
-
- */
-
 static int snd_cs4281_free(cs4281_t *chip)
 {
 	snd_cs4281_free_gameport(chip);
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index e052bd0..061e52d 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -90,7 +90,7 @@
 	snd_pmac_awacs_write(chip, val | (reg << 12));
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /* Recalibrate chip */
 static void screamer_recalibrate(pmac_t *chip)
 {
@@ -642,7 +642,7 @@
 	}
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 static void snd_pmac_awacs_suspend(pmac_t *chip)
 {
 	snd_pmac_awacs_write_noreg(chip, 1, (chip->awacs_reg[1]
@@ -676,7 +676,7 @@
 	}
 #endif
 }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 #ifdef PMAC_SUPPORT_AUTOMUTE
 /*
@@ -883,7 +883,7 @@
 	 * set lowlevel callbacks
 	 */
 	chip->set_format = snd_pmac_awacs_set_format;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	chip->suspend = snd_pmac_awacs_suspend;
 	chip->resume = snd_pmac_awacs_resume;
 #endif
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c
index f24a916..a737f29 100644
--- a/sound/ppc/daca.c
+++ b/sound/ppc/daca.c
@@ -218,7 +218,7 @@
 };
 
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 static void daca_resume(pmac_t *chip)
 {
 	pmac_daca_t *mix = chip->mixer_data;
@@ -227,7 +227,7 @@
 				  mix->amp_on ? 0x05 : 0x04);
 	daca_set_volume(mix);
 }
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
 
 
 static void daca_cleanup(pmac_t *chip)
@@ -275,7 +275,7 @@
 			return err;
 	}
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	chip->resume = daca_resume;
 #endif
 
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 080ef39..75b8b74 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -36,7 +36,7 @@
 #include <asm/pci-bridge.h>
 
 
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
 static int snd_pmac_register_sleep_notifier(pmac_t *chip);
 static int snd_pmac_unregister_sleep_notifier(pmac_t *chip);
 static int snd_pmac_suspend(snd_card_t *card, pm_message_t state);
@@ -782,7 +782,7 @@
 	}
 
 	snd_pmac_sound_feature(chip, 0);
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
 	snd_pmac_unregister_sleep_notifier(chip);
 #endif
 
@@ -1292,7 +1292,7 @@
 	/* Reset dbdma channels */
 	snd_pmac_dbdma_reset(chip);
 
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
 	/* add sleep notifier */
 	if (! snd_pmac_register_sleep_notifier(chip))
 		snd_card_set_pm_callback(chip->card, snd_pmac_suspend, snd_pmac_resume, chip);
@@ -1316,7 +1316,7 @@
  * sleep notify for powerbook
  */
 
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
 
 /*
  * Save state when going to sleep, restore it afterwards.
@@ -1414,4 +1414,5 @@
 	return 0;
 }
 
-#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
+
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
index 0a84c05..582db52 100644
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -167,7 +167,7 @@
 	void (*set_format)(pmac_t *chip);
 	void (*update_automute)(pmac_t *chip, int do_notify);
 	int (*detect_headphone)(pmac_t *chip);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	void (*suspend)(pmac_t *chip);
 	void (*resume)(pmac_t *chip);
 #endif
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 9332237..36c5d5d 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1128,7 +1128,7 @@
 	}
 }
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 /* suspend mixer */
 static void tumbler_suspend(pmac_t *chip)
 {
@@ -1370,7 +1370,7 @@
 	if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0)
 		return err;
 
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
 	chip->suspend = tumbler_suspend;
 	chip->resume = tumbler_resume;
 #endif